diff --git a/.github/workflows/delete-orphan-translation-files.yml b/.github/workflows/delete-orphan-translation-files.yml index 1862bae8b943..da1e7cec5edb 100644 --- a/.github/workflows/delete-orphan-translation-files.yml +++ b/.github/workflows/delete-orphan-translation-files.yml @@ -95,7 +95,7 @@ jobs: changes=$(git diff --name-only | wc -l) untracked=$(git status --untracked-files --short | wc -l) if [[ $changes -eq 0 ]] && [[ $untracked -eq 0 ]]; then - echo "There are no changes to commit after running src/rest/scripts/update-files.js. Exiting..." + echo "There are no changes to commit or untracked files. Exiting." exit 0 fi diff --git a/.github/workflows/sync-audit-logs.yml b/.github/workflows/sync-audit-logs.yml index d2e938bd45bf..f0226617d16b 100644 --- a/.github/workflows/sync-audit-logs.yml +++ b/.github/workflows/sync-audit-logs.yml @@ -55,7 +55,7 @@ jobs: changes=$(git diff --name-only | wc -l) untracked=$(git status --untracked-files --short | wc -l) if [[ $changes -eq 0 ]] && [[ $untracked -eq 0 ]]; then - echo "There are no changes to commit after running src/rest/scripts/update-files.js. Exiting..." + echo "There are no changes to commit or untracked files. Exiting..." exit 0 fi diff --git a/.github/workflows/sync-openapi.yml b/.github/workflows/sync-openapi.yml index e80f1a3a30e8..7e28c4294484 100644 --- a/.github/workflows/sync-openapi.yml +++ b/.github/workflows/sync-openapi.yml @@ -49,7 +49,7 @@ jobs: # Needed for gh GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_WRITEORG_PROJECT }} run: | - src/rest/scripts/update-files.js --source-repo rest-api-description --output rest github-apps webhooks rest-redirects + npm run sync-rest -- --source-repo rest-api-description --output rest github-apps webhooks rest-redirects git status echo "Deleting the cloned github/rest-api-description repo..." rm -rf rest-api-description @@ -73,7 +73,7 @@ jobs: # If nothing to commit, exit now. It's fine. No orphans. changes=$(git diff --name-only | wc -l) if [[ $changes -eq 0 ]]; then - echo "There are no changes to commit after running src/rest/scripts/update-files.js. Exiting..." + echo "There are no changes to commit after running `npm run sync-rest` Exiting..." exit 0 fi diff --git a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/index.md b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/index.md index 8f3a957f1d6d..f61d642082f2 100644 --- a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/index.md +++ b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/index.md @@ -11,6 +11,7 @@ children: - /managing-requests-for-copilot-business-in-your-organization - /revoking-access-to-copilot-for-members-of-your-organization - /reviewing-usage-data-for-github-copilot-in-your-organization + - /reviewing-changes-to-content-exclusions-for-github-copilot - /reviewing-audit-logs-for-copilot-business redirect_from: - /copilot/managing-copilot/managing-github-copilot-in-your-organization/reviewing-github-copilot-activity-in-your-organization diff --git a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot.md b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot.md similarity index 87% rename from content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot.md rename to content/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot.md index 76b2d2410cae..938e247aad59 100644 --- a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot.md +++ b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot.md @@ -1,15 +1,16 @@ --- title: Reviewing changes to content exclusions for GitHub Copilot -intro: 'You can monitor changes to content exclusions in your repositories and organizations.' +shortTitle: Content exclusion changes +intro: You can monitor changes to content exclusions in your repositories and organizations. permissions: Organization owners product: '{% data reusables.gated-features.copilot-business-and-enterprise %}' versions: feature: copilot topics: - Copilot -shortTitle: Review content exclusion changes redirect_from: - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot --- {% data reusables.copilot.content-exclusions-availability-and-beta-note %} diff --git a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/about-content-exclusions-for-github-copilot.md b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/about-content-exclusions-for-github-copilot.md deleted file mode 100644 index 860ca3edd522..000000000000 --- a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/about-content-exclusions-for-github-copilot.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: About content exclusions for GitHub Copilot -intro: 'Learn how content exclusions for {% data variables.product.prodname_copilot %} work.' -permissions: '{% data reusables.copilot.content-exclusion-permissions %}' -product: '{% data reusables.gated-features.copilot-business-and-enterprise %}' -versions: - feature: copilot -redirect_from: - - /copilot/managing-copilot-business/configuring-content-exclusions-for-github-copilot - - /copilot/managing-github-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot - - /copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot - - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/about-content-exclusions-for-github-copilot -topics: - - Copilot -shortTitle: About content exclusions ---- - -{% data reusables.copilot.content-exclusion-note %} - -You can configure {% data variables.product.prodname_copilot %} to **ignore certain files by excluding specific paths to content** in the settings for your repository or organization. - -When you specify content exclusions, there are up to three effects depending on the level of support for your IDE: - -* Code completion will not be available in the affected files. -* The content in affected files will not inform code completion suggestions in other files. -* The content in affected files will not inform {% data variables.product.prodname_copilot_chat %}'s responses. - -{% data reusables.copilot.content-exclusions-delay %} See "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/testing-changes-to-content-exclusions-in-your-ide)." - -## Availability of content exclusions - -| Tool | Code completion support | {% data variables.product.prodname_copilot_chat_short %} support | -|--------|:--------:|:--------:| -| {% data variables.product.prodname_vs %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | -| {% data variables.product.prodname_vscode %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | -| JetBrains IDEs | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | -| Vim/Neovim | {% octicon "check" aria-label="Supported" %} | Not applicable | -| Azure Data Studio | {% octicon "x" aria-label="Not supported" %} | Not applicable | -| {% data variables.product.prodname_dotcom_the_website %} | Not applicable | {% octicon "x" aria-label="Not supported" %} | - -## Limitations of content exclusions - -{% data reusables.copilot.content-exclusion-limitations %} - -## What can you exclude? - -When you specify content exclusion in the settings for a repository, you can only exclude files in that repository. - -When you specify content exclusion in the settings for an organization, you can exclude files in any Git-based repository hosted on {% data variables.product.prodname_dotcom_the_website %}, or anywhere that can be accessed using any of the following syntaxes: - -```text -http[s]://host.xz[:port]/path/to/repo.git/ - -git://host.xz[:port]/path/to/repo.git/ - -[user@]host.xz:path/to/repo.git/ - -ssh://[user@]host.xz[:port]/path/to/repo.git/ -``` - -## Who is affected by a content exclusion setting? - -{% data reusables.copilot.content-exclusions-scope %} - -{% ifversion fpt %}All exclusions, whether they are defined in repository settings or in organization settings, apply to all members of the organization who have been granted a {% data variables.product.prodname_copilot_short %} seat as part of a {% data variables.product.prodname_copilot_business_short %} subscription.{% endif %} - -{% ifversion ghec %} -You can't specify content exclusions in the settings for an enterprise. However, all content exclusions defined in organization or repository settings apply to all members of the enterprise who have been granted a {% data variables.product.prodname_copilot_short %} seat as part of a {% data variables.product.prodname_copilot_business_short %} or {% data variables.product.prodname_copilot_enterprise_short %} subscription. - -This means, for example, that if you are an admin of an organization that belongs to Enterprise X, you can set up an exclusion for files in any Git-based repositories, hosted on {% data variables.product.prodname_dotcom %} or elsewhere, and the exclusion will apply to anyone who gets their {% data variables.product.prodname_copilot_business_short %} or {% data variables.product.prodname_copilot_enterprise_short %} license from any organization in Enterprise X. - -> [!TIP] To more easily track content exclusions, create exclusions in the settings of the repository containing the affected files, or in the settings of the organization that owns the repository. -{% endif %} - -## Data sent to {% data variables.product.prodname_dotcom %} - -After you configure content exclusion, the client (for example, the {% data variables.product.prodname_copilot_short %} extension for {% data variables.product.prodname_vscode_shortname %}) sends the current repository URL to the {% data variables.product.prodname_dotcom %} server so that the server can return the correct policy to the client. These URLs are not logged anywhere. - -## Next steps - -To set up content exclusions in your repository or organization, see "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/configuring-content-exclusions-for-github-copilot)." diff --git a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot.md b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot.md deleted file mode 100644 index 587d2dccecae..000000000000 --- a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -title: Configuring content exclusions for GitHub Copilot -intro: 'You can prevent {% data variables.product.prodname_copilot %} from accessing certain content.' -permissions: '{% data reusables.copilot.content-exclusion-permissions %}' -product: '{% data reusables.gated-features.copilot-business-and-enterprise %}' -layout: inline -versions: - feature: copilot -topics: - - Copilot -shortTitle: Configure content exclusions -redirect_from: - - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/configuring-content-exclusions-for-github-copilot ---- - -{% data reusables.copilot.content-exclusions-availability-and-beta-note %} - -## Configuring content exclusions for your repository - -You can use your repository settings to specify content in your repository that {% data variables.product.prodname_copilot %} should ignore. - -{% data reusables.repositories.navigate-to-repo %} -{% data reusables.repositories.sidebar-settings %} - -1. In the "Code & automation" section of the side bar, click **{% octicon "copilot" aria-hidden="true" %} {% data variables.product.prodname_copilot_short %}**. - - If your repository inherits any exclusions from {%ifversion fpt %}its parent organization{% else %} organizations in the same enterprise{% endif %}, you'll see {%ifversion ghec %}one or more{% else %} a{% endif %} gray box{%ifversion ghec %}es{% endif %} at the top of the page containing details of these exclusions. You cannot edit these settings. - -1. In the box following "Paths to exclude in this repository," enter the paths to files from which {% data variables.product.prodname_copilot_short %} should be excluded. - - Use the format: `- "/PATH/TO/DIRECTORY/OR/FILE"`, with each path on a separate line. You can add comments by starting a line with `#`. - - > [!TIP] {% data reusables.copilot.content-exclusion-fnmatch-tip %} - -### Example of paths specified in the repository settings - -```yaml annotate -# Ignore the `/src/some-dir/kernel.rs` file in this repository. -- "/src/some-dir/kernel.rs" - -# Ignore files called `secrets.json` anywhere in this repository. -- "secrets.json" - -# Ignore all files whose names begin with `secret` anywhere in this repository. -- "secret*" - -# Ignore files whose names end with `.cfg` anywhere in this repository. -- "*.cfg" - -# Ignore all files in or below the `/scripts` directory of this repository. -- "/scripts/**" -``` - -## Configuring content exclusions for your organization - -You can use your organization settings to specify content in any Git repository that {% data variables.product.prodname_copilot %} should ignore. - -{% data reusables.profile.access_org %} -{% data reusables.profile.org_settings %} - -1. In the left sidebar, click **{% octicon "copilot" aria-hidden="true" %} {% data variables.product.prodname_copilot_short %}** then click **Content exclusion**. -1. In the box following "Repositories and paths to exclude," enter details of where {% data variables.product.prodname_copilot_short %} should be excluded. - - For each repository in which you want files to be excluded from {% data variables.product.prodname_copilot_short %}, enter a reference to the repository on one line, followed by paths to locations within the repository, with each path on a separate line. Use the following format: - - ```yaml - REPOSITORY-REFERENCE: - - "/PATH/TO/DIRECTORY/OR/FILE" - - "/PATH/TO/DIRECTORY/OR/FILE" - - ... - ``` - - Repositories can be referenced using various protocols. You can use any of the following syntaxes for `REPOSITORY-REFERENCE` and {% data variables.product.prodname_copilot_short %} will match them regardless of how the repository was cloned locally: - - ```text - http[s]://host.xz[:port]/path/to/repo.git/ - - git://host.xz[:port]/path/to/repo.git/ - - [user@]host.xz:path/to/repo.git/ - - ssh://[user@]host.xz[:port]/path/to/repo.git/ - ``` - -### Formatting tips for `REPOSITORY-REFERENCE` - -* {% data reusables.copilot.content-exclusion-fnmatch-tip %} -* The `user@` and `:port` parts of the `REPOSITORY-REFERENCE` are ignored in the calculation of which paths to ignore for a repository. -* Each repository reference can contain a single `*` wildcard. For example, `https://github.com/octo-org/*` matches all repositories in the `octo-org` organization. -* For Azure DevOps, you can use the new (dev.azure.com) or old (visualstudio.com) host format when specifying `REPOSITORY-REFERENCE`, and {% data variables.product.prodname_copilot_short %} will match them regardless of which host was used to clone the repository locally. - -### Example of repositories and paths in organization settings - -```yaml annotate -# Ignore all `.env` files at any path, in any repository. -# This setting applies to all repositories, not just to those on GitHub.com. -# This could also have been written on a single line as: -# -# "*": ["**/.env"] -"*": - - "**/.env" - -# In the `octo-repo` repository in this organization: -octo-repo: - # Ignore the `/src/some-dir/kernel.rs` file. - - "/src/some-dir/kernel.rs" - -# In the `primer/react` repository on {% data variables.product.prodname_dotcom %}: -https://github.com/primer/react.git: - # Ignore files called `secrets.json` anywhere in this repository. - - "secrets.json" - # Ignore files called `temp.rb` in or below the `/src` directory. - - "/src/**/temp.rb" - -# In the `copilot` repository of any {% data variables.product.prodname_dotcom %} organization: -git@github.com:*/copilot: - # Ignore any files in or below the `/__tests__` directory. - - "/__tests__/**" - # Ignore any files in the `/scripts` directory. - - "/scripts/*" - -# In the `gitlab-org/gitlab-runner` repository on GitLab: -git@gitlab.com:gitlab-org/gitlab-runner.git: - # Ignore the `/main_test.go` file. - - "/main_test.go" - # Ignore any files with names beginning with `server` or `session` anywhere in this repository. - - "{server,session}*" - # Ignore any files with names ending with `.md` or `.mk` anywhere in this repository. - - "*.m[dk]" - # Ignore files directly within directories such as `packages` or `packaged` anywhere in this repository. - - "**/package?/*" - # Ignore files in or below any `security` directories, anywhere in this repository. - - "**/security/**" -``` - -## Next steps - -To test your changes, see "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/testing-changes-to-content-exclusions-in-your-ide)." diff --git a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/excluding-content-from-github-copilot.md b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/excluding-content-from-github-copilot.md new file mode 100644 index 000000000000..46fc2ee930d4 --- /dev/null +++ b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/excluding-content-from-github-copilot.md @@ -0,0 +1,190 @@ +--- +title: Excluding content from GitHub Copilot +shortTitle: Exclude content from Copilot +intro: 'You can prevent {% data variables.product.prodname_copilot_short %} from accessing certain content.' +permissions: '{% data reusables.copilot.content-exclusion-permissions %}' +product: '{% data reusables.gated-features.copilot-business-and-enterprise %}' +layout: inline +versions: + feature: copilot +redirect_from: + - /copilot/managing-copilot-business/configuring-content-exclusions-for-github-copilot + - /copilot/managing-github-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/about-content-exclusions-for-github-copilot + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/about-content-exclusions-for-github-copilot + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/configuring-content-exclusions-for-github-copilot + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/testing-changes-to-content-exclusions-in-your-ide + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/configuring-content-exclusions-for-github-copilot + - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/testing-changes-to-content-exclusions-in-your-ide +topics: + - Copilot +--- + +## About content exclusions for {% data variables.product.prodname_copilot_short %} + +{% data reusables.copilot.content-exclusion-note %} + +You can use content exclusions to configure {% data variables.product.prodname_copilot_short %} to ignore certain files in a repository or organization. When you exclude content from {% data variables.product.prodname_copilot_short %}: + +* Code completion will not be available in the affected files. +* The content in affected files will not inform code completion suggestions in other files. +* The content in affected files will not inform {% data variables.product.prodname_copilot_chat %}'s responses. + +{% data reusables.copilot.content-exclusions-scope %} + +### Limitations of content exclusions + +Content exclusions are not currently available for Copilot Chat in Visual Studio, Copilot Chat in GitHub.com, or code completion in Azure Data Studio. Additionally: + +{% data reusables.copilot.content-exclusion-limitations %} + +### Data sent to {% data variables.product.prodname_dotcom %} + +After you configure content exclusion, the client (for example, the {% data variables.product.prodname_copilot_short %} extension for {% data variables.product.prodname_vscode_shortname %}) sends the current repository URL to the {% data variables.product.prodname_dotcom %} server so that the server can return the correct policy to the client. These URLs are not logged anywhere. + +## Configuring content exclusions for your repository + +You can use your repository settings to specify content in your repository that {% data variables.product.prodname_copilot %} should ignore. + +{% data reusables.repositories.navigate-to-repo %} +{% data reusables.repositories.sidebar-settings %} + +1. In the "Code & automation" section of the side bar, click **{% octicon "copilot" aria-hidden="true" %} {% data variables.product.prodname_copilot_short %}**. + + If your repository inherits any exclusions from {%ifversion fpt %}its parent organization{% else %} organizations in the same enterprise{% endif %}, you'll see {%ifversion ghec %}one or more{% else %} a{% endif %} gray box{%ifversion ghec %}es{% endif %} at the top of the page containing details of these exclusions. You cannot edit these settings. + +1. In the box following "Paths to exclude in this repository," enter the paths to files from which {% data variables.product.prodname_copilot_short %} should be excluded. + + Use the format: `- "/PATH/TO/DIRECTORY/OR/FILE"`, with each path on a separate line. You can add comments by starting a line with `#`. + + > [!TIP] {% data reusables.copilot.content-exclusion-fnmatch-tip %} + +### Example of paths specified in the repository settings + +```yaml annotate +# Ignore the `/src/some-dir/kernel.rs` file in this repository. +- "/src/some-dir/kernel.rs" + +# Ignore files called `secrets.json` anywhere in this repository. +- "secrets.json" + +# Ignore all files whose names begin with `secret` anywhere in this repository. +- "secret*" + +# Ignore files whose names end with `.cfg` anywhere in this repository. +- "*.cfg" + +# Ignore all files in or below the `/scripts` directory of this repository. +- "/scripts/**" +``` + +## Configuring content exclusions for your organization + +You can use your organization settings to specify content in any Git repository that {% data variables.product.prodname_copilot %} should ignore. + +{% data reusables.profile.access_org %} +{% data reusables.profile.org_settings %} + +1. In the left sidebar, click **{% octicon "copilot" aria-hidden="true" %} {% data variables.product.prodname_copilot_short %}** then click **Content exclusion**. +1. In the box following "Repositories and paths to exclude," enter details of where {% data variables.product.prodname_copilot_short %} should be excluded. + + For each repository in which you want files to be excluded from {% data variables.product.prodname_copilot_short %}, enter a reference to the repository on one line, followed by paths to locations within the repository, with each path on a separate line. Use the following format, replacing `REPOSITORY-REFERENCE` with a reference to the repository that contains the files you'd like to exclude: + + ```yaml + REPOSITORY-REFERENCE: + - "/PATH/TO/DIRECTORY/OR/FILE" + - "/PATH/TO/DIRECTORY/OR/FILE" + - ... + ``` + + Repositories can be referenced using various protocols. You can use any of the following syntaxes for `REPOSITORY-REFERENCE` and {% data variables.product.prodname_copilot_short %} will match them regardless of how the repository was cloned locally: + + ```text + http[s]://host.xz[:port]/path/to/repo.git/ + + git://host.xz[:port]/path/to/repo.git/ + + [user@]host.xz:path/to/repo.git/ + + ssh://[user@]host.xz[:port]/path/to/repo.git/ + ``` + + The `user@` and `:port` parts of the `REPOSITORY-REFERENCE` are ignored in the calculation of which paths to ignore for a repository. + + For Azure DevOps, you can use the new (dev.azure.com) or old (visualstudio.com) host format when specifying `REPOSITORY-REFERENCE`, and {% data variables.product.prodname_copilot_short %} will match them regardless of which host was used to clone the repository locally. + + > [!TIP] {% data reusables.copilot.content-exclusion-fnmatch-tip %} + +### Example of repositories and paths in organization settings + +```yaml annotate +# Ignore all `.env` files at any path, in any repository. +# This setting applies to all repositories, not just to those on GitHub.com. +# This could also have been written on a single line as: +# +# "*": ["**/.env"] +"*": + - "**/.env" + +# In the `octo-repo` repository in this organization: +octo-repo: + # Ignore the `/src/some-dir/kernel.rs` file. + - "/src/some-dir/kernel.rs" + +# In the `primer/react` repository on {% data variables.product.prodname_dotcom %}: +https://github.com/primer/react.git: + # Ignore files called `secrets.json` anywhere in this repository. + - "secrets.json" + # Ignore files called `temp.rb` in or below the `/src` directory. + - "/src/**/temp.rb" + +# In the `copilot` repository of any {% data variables.product.prodname_dotcom %} organization: +git@github.com:*/copilot: + # Ignore any files in or below the `/__tests__` directory. + - "/__tests__/**" + # Ignore any files in the `/scripts` directory. + - "/scripts/*" + +# In the `gitlab-org/gitlab-runner` repository on GitLab: +git@gitlab.com:gitlab-org/gitlab-runner.git: + # Ignore the `/main_test.go` file. + - "/main_test.go" + # Ignore any files with names beginning with `server` or `session` anywhere in this repository. + - "{server,session}*" + # Ignore any files with names ending with `.md` or `.mk` anywhere in this repository. + - "*.m[dk]" + # Ignore files directly within directories such as `packages` or `packaged` anywhere in this repository. + - "**/package?/*" + # Ignore files in or below any `security` directories, anywhere in this repository. + - "**/security/**" +``` + +## Testing changes to content exclusions + +You can use your IDE to confirm that your changes to content exclusions are working as expected. + +### Propagate content exclusion changes to your IDE + +After you add or change content exclusions, it can take up to 30 minutes to take effect in IDEs where the settings are already loaded. If you don't want to wait, you can manually reload the content exclusion settings using the following instructions. + +* **For JetBrains IDEs and {% data variables.product.prodname_vs %}**, reload the content exclusion settings by closing and reopening the application. +* **For {% data variables.product.prodname_vscode %}**, use the following steps to reload the content exclusion settings: + 1. Access the Command Palette. For example, by pressing Shift+Command+P (Mac) / Ctrl+Shift+P (Windows/Linux). + 1. Type: `reload`. + 1. Select **Developer: Reload Window**. +* **For Vim/Neovim**, content exclusions are automatically fetched from {% data variables.product.prodname_dotcom %} each time you open a file. + +### Test your content exclusions + +There are a few different ways to test your content exclusions, depending on which IDE you're using. + +1. Open a file that you expect to be affected by your content exclusions. +1. Use one or more of the following techniques to test if content is being excluded: + * **In JetBrains IDEs, {% data variables.product.prodname_vs %}, and {% data variables.product.prodname_vscode %}**, check the {% data variables.product.prodname_copilot_short %} icon in the status bar. If a {% data variables.product.prodname_copilot_short %} content exclusion applies to the file, the {% data variables.product.prodname_copilot_short %} icon will have a diagonal line through it. Hover over the icon to see whether an organization or the parent repository disabled {% data variables.product.prodname_copilot_short %} for the file. + * **In JetBrains IDEs and {% data variables.product.prodname_vscode %}**, you can also test content exclusions in {% data variables.product.prodname_copilot_chat_short %}. Open the {% data variables.product.prodname_copilot_chat_short %} window, and ask {% data variables.product.prodname_copilot_chat_short %} a question about the excluded file. If your content is excluded successfully, {% data variables.product.prodname_copilot_short %} will be unable to answer your question, and will explain that some files were excluded from the conversation due to content exclusion rules. + * **In Vim/Neovim**, begin typing in the file. If {% data variables.product.prodname_copilot %} no longer provides inline suggestions as you type, the file is excluded. + +## Further reading + +* "[AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-access-to-github-copilot-in-your-organization/reviewing-changes-to-content-exclusions-for-github-copilot)" diff --git a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/index.md b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/index.md index e838d0245a46..e5d01f518b5d 100644 --- a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/index.md +++ b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/index.md @@ -8,10 +8,8 @@ topics: - Copilot children: - /managing-policies-for-copilot-in-your-organization - - /about-content-exclusions-for-github-copilot - - /configuring-content-exclusions-for-github-copilot - - /testing-changes-to-content-exclusions-in-your-ide - - /reviewing-changes-to-content-exclusions-for-github-copilot + - /excluding-content-from-github-copilot redirect_from: - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization --- + diff --git a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/testing-changes-to-content-exclusions-in-your-ide.md b/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/testing-changes-to-content-exclusions-in-your-ide.md deleted file mode 100644 index 1b400e1ba993..000000000000 --- a/content/copilot/managing-copilot/managing-github-copilot-in-your-organization/setting-policies-for-copilot-in-your-organization/testing-changes-to-content-exclusions-in-your-ide.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Testing changes to content exclusions in your IDE -intro: 'You can confirm your changes to content exclusions work as expected using your IDE.' -permissions: '{% data reusables.copilot.content-exclusion-permissions %}' -product: '{% data reusables.gated-features.copilot-business-and-enterprise %}' -versions: - feature: copilot -topics: - - Copilot -shortTitle: Test content exclusions -redirect_from: - - /copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/testing-changes-to-content-exclusions-in-your-ide ---- - -{% data reusables.copilot.content-exclusions-availability-and-beta-note %} - -{% vscode %} - -## Propagating content exclusion changes to {% data variables.product.prodname_vscode %} - -In {% data variables.product.prodname_vscode_shortname %}, you can wait up to 30 minutes to see the effect of a settings change, or you can manually reload content exclusion settings as follows: - -1. Access the Command Palette. For example, by pressing Shift+Command+P (Mac) / Ctrl+Shift+P (Windows/Linux). -1. Type: `reload`. -1. Select **Developer: Reload Window**. - -## Testing changes to content exclusions in {% data variables.product.prodname_vscode %} - -After content exclusion changes propagate to {% data variables.product.prodname_vscode_shortname %}, the {% data variables.product.prodname_copilot_short %} icon indicates when {% data variables.product.prodname_copilot_short %} has been disabled by a content exclusion. - -1. Open a file that you expect to be affected by your content exclusions. - - If a {% data variables.product.prodname_copilot_short %} content exclusion applies to this file, the {% data variables.product.prodname_copilot_short %} icon in the status bar has a diagonal line through it. - -1. Hover over the {% data variables.product.prodname_copilot_short %} icon. A popup message tells you whether an organization or the parent repository disabled {% data variables.product.prodname_copilot_short %} for this file. - - ![Screenshot of the {% data variables.product.prodname_copilot_short %} disabled popup in the {% data variables.product.prodname_vscode_shortname %} toolbar.](/assets/images/help/copilot/copilot-disabled-for-repo.png) - -1. Optionally, you can also test content exclusions in {% data variables.product.prodname_copilot_chat_short %}. Open the {% data variables.product.prodname_copilot_chat_short %} window by clicking the {% data variables.product.prodname_copilot_chat_short %} icon in the activity bar. - - ![Screenshot of the {% data variables.product.prodname_copilot_chat_short %} icon in the Activity Bar.](/assets/images/help/copilot/vsc-copilot-chat-icon.png) - -{% data reusables.copilot.test-content-exclusions-chat %} - -{% endvscode %} - -{% visualstudio %} - -## Propagating content exclusion changes to {% data variables.product.prodname_vs %} - -In {% data variables.product.prodname_vs %}, you can wait up to 30 minutes to see the effect of a settings change, or you can manually reload the content exclusion settings by closing and reopening the application. - -## Testing changes to content exclusions in {% data variables.product.prodname_vs %} - -In {% data variables.product.prodname_vs %}, the {% data variables.product.prodname_copilot_short %} icon indicates when {% data variables.product.prodname_copilot_short %} has been disabled by a content exclusion. - -1. Open a file that you expect to be affected by your content exclusions. - - If a {% data variables.product.prodname_copilot_short %} content exclusion applies to this file, the {% data variables.product.prodname_copilot_short %} icon in the status bar has a diagonal line through it. - -1. Hover over the {% data variables.product.prodname_copilot_short %} icon. A popup message tells you whether an organization or the parent repository disabled {% data variables.product.prodname_copilot_short %} for this file. - - ![Screenshot of the {% data variables.product.prodname_copilot_short %} disabled popup in the {% data variables.product.prodname_vscode_shortname %} toolbar.](/assets/images/help/copilot/copilot-disabled-for-repo.png) - -{% endvisualstudio %} - -{% jetbrains %} - -## Propagating content exclusion changes to JetBrains IDEs - -In supported JetBrains IDEs, you can wait up to 30 minutes to see the effect of a settings change, or you can manually reload the content exclusion settings by closing and reopening the application. - -## Testing changes to content exclusions in JetBrains IDEs - -In supported JetBrains IDEs, the {% data variables.product.prodname_copilot_short %} icon indicates when {% data variables.product.prodname_copilot_short %} has been disabled by a content exclusion. - -1. Open a file that you expect to be affected by your content exclusions. - - If a {% data variables.product.prodname_copilot_short %} content exclusion applies to this file, the {% data variables.product.prodname_copilot_short %} icon in the status bar has a diagonal line through it. - -1. Hover over the {% data variables.product.prodname_copilot_short %} icon. A popup message tells you whether an organization or the parent repository disabled {% data variables.product.prodname_copilot_short %} for this file. - - ![Screenshot of the {% data variables.product.prodname_copilot_short %} disabled popup in the {% data variables.product.prodname_vscode_shortname %} toolbar.](/assets/images/help/copilot/copilot-disabled-for-repo.png) - -1. Optionally, you can also test content exclusions in {% data variables.product.prodname_copilot_chat_short %}. Open the {% data variables.product.prodname_copilot_chat_short %} window by clicking the **{% data variables.product.prodname_copilot_chat_short %}** icon at the right side of the JetBrains IDE window. - - ![Screenshot of the {% data variables.product.prodname_copilot_chat_short %} icon in the Activity Bar.](/assets/images/help/copilot/jetbrains-copilot-chat-icon.png) - -{% data reusables.copilot.test-content-exclusions-chat %} - -{% endjetbrains %} - -{% vimneovim %} - -## Propagating content exclusion changes to Vim/Neovim - -If you are working in Vim/Neovim, content exclusions are automatically fetched from {% data variables.product.prodname_dotcom %} each time you open a file. - -## Testing changes to content exclusions in Vim/Neovim - -1. Open a file that you expect to be affected by your content exclusions. -1. Begin typing. If {% data variables.product.prodname_copilot %} no longer provides inline suggestions as you type, the file is excluded. - -{% endvimneovim %} diff --git a/content/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics.md b/content/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics.md index 8b0fbe2282e8..c0afe350e833 100644 --- a/content/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics.md +++ b/content/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/classifying-your-repository-with-topics.md @@ -32,9 +32,9 @@ Repository admins can add any topics they'd like to a repository. Helpful topics You can search for repositories that are associated with a particular topic. For more information, see "[AUTOTITLE](/search-github/searching-on-github/searching-for-repositories#search-by-topic)." You can also search for a list of topics on {% data variables.product.product_name %}. For more information, see "[AUTOTITLE](/search-github/searching-on-github/searching-topics)." When creating a topic: -* use lowercase letters, numbers, and hyphens. -* use 50 characters or less. -* add no more than 20 topics. +* Use lowercase letters, numbers, and hyphens. +* Use 50 characters or less. +* Add no more than 20 topics. ## Adding topics to your repository diff --git a/data/reusables/copilot/content-exclusions-scope.md b/data/reusables/copilot/content-exclusions-scope.md index 6c4c269d0b95..a93d9ac08418 100644 --- a/data/reusables/copilot/content-exclusions-scope.md +++ b/data/reusables/copilot/content-exclusions-scope.md @@ -1,5 +1,11 @@ -A content exclusion setting **only applies to people who meet each of the following criteria**: -* They have been granted a seat as part of a {% data variables.product.prodname_copilot_for_business %} or {% data variables.product.prodname_copilot_enterprise %} subscription -* They are members of the same {% ifversion fpt %}organization{% else %}enterprise{% endif %} in which the content exclusion is configured +{% ifversion fpt %} + +Content exclusion settings only apply to members of the organization in which the content exclusion is configured, who have been granted a seat as part of a {% data variables.product.prodname_copilot_for_business %} or {% data variables.product.prodname_copilot_enterprise %} subscription. + +{% else %} + +You can only specify content exclusions in the settings for an organization or repository, not in the settings for an enterprise. Content exclusion settings defined in an organization or repository within an enterprise will apply to all members of the enterprise who have been granted a seat as part of a {% data variables.product.prodname_copilot_for_business %} or {% data variables.product.prodname_copilot_enterprise %} subscription. + +{% endif %} Anyone else who can access the specified files will still see code completion suggestions and {% data variables.product.prodname_copilot_chat %} responses referencing the specified files. diff --git a/package.json b/package.json index 6766cd08355b..ae780e584e6c 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "start-all-languages": "cross-env NODE_ENV=development tsx src/frame/server.ts", "start-for-playwright": "cross-env ROOT=src/fixtures/fixtures TRANSLATIONS_FIXTURE_ROOT=src/fixtures/fixtures/translations ENABLED_LANGUAGES=en,ja NODE_ENV=test tsx src/frame/server.ts", "symlink-from-local-repo": "node src/early-access/scripts/symlink-from-local-repo.js", - "sync-rest": "node src/rest/scripts/update-files.js", + "sync-rest": "tsx src/rest/scripts/update-files.ts", "sync-search": "cross-env NODE_OPTIONS='--max_old_space_size=8192' start-server-and-test sync-search-server 4002 sync-search-indices", "sync-search-ghes-release": "cross-env GHES_RELEASE=1 start-server-and-test sync-search-server 4002 sync-search-indices", "sync-search-indices": "node src/search/scripts/sync-search-indices.js", diff --git a/src/automated-pipelines/lib/update-markdown.js b/src/automated-pipelines/lib/update-markdown.js index f7a9f55822e0..ba9a13e34c7c 100644 --- a/src/automated-pipelines/lib/update-markdown.js +++ b/src/automated-pipelines/lib/update-markdown.js @@ -310,6 +310,10 @@ async function getIndexFileVersions(directory, files) { `File ${filepath} does not exist while assembling directory index.md files to create parent version.`, ) } + // If not a markdown(x) file, skip it + if (!file.endsWith('.md') && !file.endsWith('.mdx')) { + return + } const { data } = matter(await readFile(filepath, 'utf-8')) if (!data || !data.versions) { throw new Error(`Frontmatter in ${filepath} does not contain versions.`) diff --git a/src/codeql-cli/README.md b/src/codeql-cli/README.md index e7840ae96a54..4ff82fd898ed 100644 --- a/src/codeql-cli/README.md +++ b/src/codeql-cli/README.md @@ -24,9 +24,9 @@ To run the CodeQL CLI pipeline locally: ## About this directory -- `src/rest/lib/config.json` - A configuration file used to specify metadata about the REST pipeline. -- `src/rest/scripts` - The scripts and source code used run the CodeQL CLI pipeline. - - `src/rest/scripts/sync.js` - The entrypoint script that runs the CodeQL CLI pipeline. +- `src/codeql-cli/lib/config.json` - A configuration file used to specify metadata about the CodeQL CLI pipeline. +- `src/codeql-cli/scripts` - The scripts and source code used run the CodeQL CLI pipeline. + - `src/codeql-cli/scripts/sync.js` - The entrypoint script that runs the CodeQL CLI pipeline. ## Content team diff --git a/src/ghes-releases/lib/release-templates/release-steps-5.md b/src/ghes-releases/lib/release-templates/release-steps-5.md index 12c8fb77caf7..15b9e3501a74 100644 --- a/src/ghes-releases/lib/release-templates/release-steps-5.md +++ b/src/ghes-releases/lib/release-templates/release-steps-5.md @@ -133,7 +133,7 @@ The benefit of the first method is that you don't need to deal with merging two - [ ] To update the OpenAPI data, run the following command. ```shell - src/rest/scripts/update-files.js --source-repo rest-api-description --output rest github-apps webhooks rest-redirects + npm run sync-rest -- --source-repo rest-api-description --output rest github-apps webhooks rest-redirects ``` You may see an error that indicates that "...you must have the GITHUB_TOKEN environment variable set to access the programmatic access and resource files via the GitHub REST API." You can ignore this error. diff --git a/src/github-apps/README.md b/src/github-apps/README.md index 67848399f773..2f9389c1ae0f 100644 --- a/src/github-apps/README.md +++ b/src/github-apps/README.md @@ -34,7 +34,8 @@ If the OpenAPI has changed, you will need to first wait for the OpenAPI to be me To run the GitHub Apps pipeline locally: 1. Clone the [`github/rest-api-description`](https://github.com/github/rest-api-description) repository inside your local `docs-internal` repository. -1. Run `src/rest/scripts/update-files.js -s rest-api-description -o github-apps`. +1. Set a `GITHUB_TOKEN` in your `.env` with (classic) `repo` scopes & enable SSO for the github org. +1. Run `npm run sync-rest -- -s rest-api-description -o github-apps`. ## About this directory diff --git a/src/rest/README.md b/src/rest/README.md index 42332f0d324f..bb89442099a2 100644 --- a/src/rest/README.md +++ b/src/rest/README.md @@ -14,7 +14,7 @@ A [workflow](.github/workflows/sync-openapi.yml) is used to trigger the automati - REST - Webhooks -The workflow automatically creates a pull request with the changes (for all three pipelines) and the label `github-openapi-bot`. The workflow runs the `src/rest/scripts/update-files.js` script, which creates, deletes, or updates Markdown files in the `content/rest` directory. +The workflow automatically creates a pull request with the changes (for all three pipelines) and the label `github-openapi-bot`. The workflow runs the `npm run sync-rest` script, which creates, deletes, or updates Markdown files in the `content/rest` directory. ### Triggering the workflow sooner than the scheduled time @@ -35,7 +35,8 @@ Then, you can manually sync the data used by the REST, Webhooks, and GitHub App To run the REST pipeline locally: 1. Clone the [`github/rest-api-description`](https://github.com/github/rest-api-description) repository inside your local `docs-internal` repository. -1. Run `src/rest/scripts/update-files.js -s rest-api-description -o rest`. Note, by default `-o rest` is specified, so you can omit it. +1. Set a `GITHUB_TOKEN` in your `.env` with (classic) `repo` scopes & enable SSO for the github org. +1. Run `npm run sync-rest -- -s rest-api-description -o rest`. Note, by default `-o rest` is specified, so you can omit it. ## About this directory @@ -45,7 +46,7 @@ To run the REST pipeline locally: - `src/rest/lib` - The source code used in production for the automated documentation generated by the REST pipeline and configuration files edited by content and engineering team members. - `src/rest/lib/config.json` - A configuration file used to specify metadata about the REST pipeline. - `src/rest/scripts` - The scripts and source code used run the REST pipeline, which updates the `src/rest/data` directory. - - `src/rest/scripts/update-files.js` - The entrypoint script that runs the REST pipeline. + - `src/rest/scripts/update-files.ts` - The entrypoint script that runs the REST pipeline. - `src/rest/tests` - The tests used to verify the REST pipeline. ## Configuring the pipeline diff --git a/src/rest/scripts/README.md b/src/rest/scripts/README.md index bed3aa0c8426..1c0cc4f3d4ca 100644 --- a/src/rest/scripts/README.md +++ b/src/rest/scripts/README.md @@ -1,8 +1,8 @@ # REST scripts -Writers run the [update-files.js](./update-files.js) script to get the latest dereferenced OpenAPI schema files. +Writers run the [update-files.ts](./update-files.ts) script to get the latest dereferenced OpenAPI schema files. ``` -src/rest/scripts/update-files.js +npm run sync-rest ``` These scripts update the dereferenced OpenAPI files to create [the decorated files](../../src/rest/data) used to render REST docs. See the [`src/rest/README`](../../src/rest/README.md) @@ -20,7 +20,7 @@ Writers and developers depend on this script to preview OpenAPI changes in the d ## Production `--decorate-only` option -When changes to the OpenAPI are merged to the default branch of the `github/github` repository, a pull request is automatically opened with the updated dereferenced OpenAPI files. When pull requests are authored by `github-openapi-bot`, a CI test runs the `src/rest/scripts/update-files.js` script with the `--decorate-only` option. The `--decorate-only` option only decorates the dereferenced OpenAPI files, using the existing dereferenced OpenAPI schema files, and checks those changes in to the existing branch. The `--decorate-only` option is only used by a 🤖 and is only used on production dereferenced OpenAPI schema files. +When changes to the OpenAPI are merged to the default branch of the `github/github` repository, a pull request is automatically opened with the updated dereferenced OpenAPI files. When pull requests are authored by `github-openapi-bot`, a CI test runs the `npm run sync-rest` script with the `--decorate-only` option. The `--decorate-only` option only decorates the dereferenced OpenAPI files, using the existing dereferenced OpenAPI schema files, and checks those changes in to the existing branch. The `--decorate-only` option is only used by a 🤖 and is only used on production dereferenced OpenAPI schema files. The `.github/workflows/openapi-schema-check.yml` CI test checks that the dereferenced and decorated schema files match. If the files don't match, potential causes could be: - something went wrong when the schema changes (created by `github-openapi-bot`) were merged into another branch @@ -28,4 +28,4 @@ The `.github/workflows/openapi-schema-check.yml` CI test checks that the derefer ⚠️ Only do this if you know exactly what the `--decorate-only` option does. ⚠️ -If you know that the dereferenced schema files are correct, you can run the `src/rest/scripts/update-files.js --decorate-only` command on the branch locally to update the decorated files in your branch. +If you know that the dereferenced schema files are correct, you can run the `npm run sync-rest -- --decorate-only` command on the branch locally to update the decorated files in your branch. diff --git a/src/rest/scripts/update-files.js b/src/rest/scripts/update-files.ts similarity index 93% rename from src/rest/scripts/update-files.js rename to src/rest/scripts/update-files.ts index f6264d930c78..7873887dd427 100755 --- a/src/rest/scripts/update-files.js +++ b/src/rest/scripts/update-files.ts @@ -17,12 +17,12 @@ import { fileURLToPath } from 'url' import walk from 'walk-sync' import { existsSync } from 'fs' -import { syncRestData, getOpenApiSchemaFiles } from './utils/sync.js' -import { validateVersionsOptions } from './utils/get-openapi-schemas.js' -import { allVersions } from '#src/versions/lib/all-versions.js' -import { syncWebhookData } from '../../webhooks/scripts/sync.js' -import { syncGitHubAppsData } from '../../github-apps/scripts/sync.js' -import { syncRestRedirects } from './utils/get-redirects.js' +import { syncRestData, getOpenApiSchemaFiles } from './utils/sync' +import { validateVersionsOptions } from './utils/get-openapi-schemas' +import { allVersions } from '@/versions/lib/all-versions' +import { syncWebhookData } from '../../webhooks/scripts/sync' +import { syncGitHubAppsData } from '../../github-apps/scripts/sync' +import { syncRestRedirects } from './utils/get-redirects' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const TEMP_OPENAPI_DIR = path.join(__dirname, '../../../rest-api-description/openApiTemp') @@ -30,7 +30,9 @@ const TEMP_BUNDLED_OPENAPI_DIR = path.join(TEMP_OPENAPI_DIR, 'bundled') const GITHUB_REP_DIR = '../github' const REST_API_DESCRIPTION_ROOT = 'rest-api-description' const REST_DESCRIPTION_DIR = path.join(REST_API_DESCRIPTION_ROOT, 'descriptions-next') -const VERSION_NAMES = JSON.parse(await readFile('src/rest/lib/config.json', 'utf8')).versionMapping +const VERSION_NAMES: Record = JSON.parse( + await readFile('src/rest/lib/config.json', 'utf8'), +).versionMapping const noConfig = ['rest-redirects'] program @@ -105,7 +107,10 @@ async function main() { // so that we don't spend time generating data files for them. if (sourceRepo === REST_API_DESCRIPTION_ROOT) { const derefDir = await readdir(TEMP_OPENAPI_DIR) - const currentOpenApiVersions = Object.values(allVersions).map((elem) => elem.openApiVersionName) + // TODO: After migrating all-version.js to TypeScript, we can remove the type assertion + const currentOpenApiVersions = Object.values(allVersions).map( + (elem) => (elem as any).openApiVersionName, + ) for (const schema of derefDir) { // if the schema does not start with a current version name, delete it @@ -162,7 +167,7 @@ async function main() { ) } -async function getBundledFiles() { +async function getBundledFiles(): Promise { // Get the github/github repo branch name and pull latest const githubBranch = execSync('git rev-parse --abbrev-ref HEAD', { cwd: GITHUB_REP_DIR }) .toString() @@ -197,7 +202,7 @@ async function getBundledFiles() { } } -async function getBundlerOptions() { +async function getBundlerOptions(): Promise { let includeParams = ['--generate_dref_json_only'] if (versions) { @@ -213,7 +218,7 @@ async function getBundlerOptions() { return includeParams.join(' ') } -async function validateInputParameters() { +async function validateInputParameters(): Promise { // The `--versions` option cannot be used // with the `--include-deprecated` option if (includeDeprecated && versions) { @@ -248,7 +253,7 @@ async function validateInputParameters() { // the short name of the version defined in lib/allVersions.js. // This function also translates calendar-date format from .2022-11-28 to // -2022-11-28 -export async function normalizeDataVersionNames(sourceDirectory) { +export async function normalizeDataVersionNames(sourceDirectory: string): Promise { const schemas = await readdir(sourceDirectory) for (const schema of schemas) { @@ -259,8 +264,8 @@ export async function normalizeDataVersionNames(sourceDirectory) { // Update the version name to use docs convention, e.g., // api.github.com.2022-11-28 -> fpt.2022-11-28 const docsBaseName = baseName.replace( - matchingSourceVersion, - VERSION_NAMES[matchingSourceVersion], + matchingSourceVersion!, + VERSION_NAMES[matchingSourceVersion!], ) // Match a calendar version if it exists, e.g., .2022-11-28 const regex = /.\d{4}-\d{2}-\d{2}/ diff --git a/src/rest/scripts/utils/get-body-params.js b/src/rest/scripts/utils/get-body-params.ts similarity index 73% rename from src/rest/scripts/utils/get-body-params.js rename to src/rest/scripts/utils/get-body-params.ts index 2d76636e4c4b..d676a73b1878 100644 --- a/src/rest/scripts/utils/get-body-params.js +++ b/src/rest/scripts/utils/get-body-params.ts @@ -1,5 +1,39 @@ #!/usr/bin/env node -import { renderContent } from '#src/content-render/index.js' +import { renderContent } from '@/content-render/index' + +interface Schema { + oneOf?: any[] + type?: string + items?: any + properties?: Record + required?: string[] + additionalProperties?: any + description?: string + enum?: string[] + nullable?: boolean + allOf?: any[] + anyOf?: any[] + [key: string]: any +} + +export interface TransformedParam { + type: string + name: string + description: string + isRequired?: boolean + in?: string + childParamsGroups?: TransformedParam[] + enum?: string[] + oneOfObject?: boolean + default?: any +} + +interface BodyParamProps { + paramKey?: string + required?: string[] + childParamsGroups?: TransformedParam[] + topLevel?: boolean +} // If there is a oneOf at the top level, then we have to present just one // in the docs. We don't currently have a convention for showing more than one @@ -8,14 +42,16 @@ import { renderContent } from '#src/content-render/index.js' // Currently there aren't very many operations that require this treatment. // As an example, the 'Add status check contexts' and 'Set status check contexts' // operations have a top-level oneOf. - -async function getTopLevelOneOfProperty(schema) { +async function getTopLevelOneOfProperty( + schema: Schema, +): Promise<{ properties: Record; required: string[] }> { if (!schema.oneOf) { throw new Error('Schema does not have a requestBody oneOf property defined') } if (!(Array.isArray(schema.oneOf) && schema.oneOf.length > 0)) { throw new Error('Schema requestBody oneOf property is not an array') } + // When a oneOf exists but the `type` differs, the case has historically // been that the alternate option is an array, where the first option // is the array as a property of the object. We need to ensure that the @@ -39,8 +75,8 @@ async function getTopLevelOneOfProperty(schema) { } // Gets the body parameters for a given schema recursively. -export async function getBodyParams(schema, topLevel = false) { - const bodyParametersParsed = [] +export async function getBodyParams(schema: Schema, topLevel = false): Promise { + const bodyParametersParsed: TransformedParam[] = [] const schemaObject = schema.oneOf && topLevel ? await getTopLevelOneOfProperty(schema) : schema const properties = schemaObject.properties || {} const required = schemaObject.required || [] @@ -48,7 +84,7 @@ export async function getBodyParams(schema, topLevel = false) { // Most operation requestBody schemas are objects. When the type is an array, // there will not be properties on the `schema` object. if (topLevel && schema.type === 'array') { - const childParamsGroups = [] + const childParamsGroups: TransformedParam[] = [] const arrayType = schema.items.type const paramType = [schema.type] if (arrayType === 'object') { @@ -76,7 +112,7 @@ export async function getBodyParams(schema, topLevel = false) { ? param.additionalProperties.type : [param.additionalProperties.type] : [] - const childParamsGroups = [] + const childParamsGroups: TransformedParam[] = [] // If the parameter is an array or object there may be child params // If the parameter has oneOf or additionalProperties, they need to be @@ -88,7 +124,7 @@ export async function getBodyParams(schema, topLevel = false) { // Create a snapshot of dependencies for a repository // Update a gist if (param.additionalProperties && additionalPropertiesType.includes('object')) { - const keyParam = { + const keyParam: TransformedParam = { type: 'object', name: 'key', description: await renderContent( @@ -99,11 +135,13 @@ export async function getBodyParams(schema, topLevel = false) { default: param.default, childParamsGroups: [], } - keyParam.childParamsGroups.push(...(await getBodyParams(param.additionalProperties, false))) + if (keyParam.childParamsGroups) { + keyParam.childParamsGroups.push(...(await getBodyParams(param.additionalProperties, false))) + } childParamsGroups.push(keyParam) - } else if (paramType && paramType.includes('array') && param.items) { - if (param.items && param.items.oneOf) { - if (param.items.oneOf.every((object) => object.type === 'object')) { + } else if (paramType.includes('array') && param.items) { + if (param.items.oneOf) { + if (param.items.oneOf.every((object: TransformedParam) => object.type === 'object')) { paramType.splice(paramType.indexOf('array'), 1, `array of objects`) param.oneOfObject = true childParamsGroups.push(...(await getOneOfChildParams(param.items))) @@ -116,31 +154,25 @@ export async function getBodyParams(schema, topLevel = false) { if (arrayType === 'object') { childParamsGroups.push(...(await getBodyParams(param.items, false))) } - // If the type is an enumerated list of strings if (arrayType === 'string' && param.items.enum) { param.description += `${ param.description ? '\n' : '' - }Supported values are: ${param.items.enum - .map((lang) => `${lang}`) - .join(', ')}` + }Supported values are: ${param.items.enum.map((lang: string) => `${lang}`).join(', ')}` } } - } else if (paramType && paramType.includes('object')) { - if (param && param.oneOf) { - if (param.oneOf.every((object) => object.type === 'object')) { + } else if (paramType.includes('object')) { + if (param.oneOf) { + if (param.oneOf.every((object: TransformedParam) => object.type === 'object')) { param.oneOfObject = true childParamsGroups.push(...(await getOneOfChildParams(param))) } } else { childParamsGroups.push(...(await getBodyParams(param, false))) } - } else if (param && param.oneOf) { - // get concatenated description and type - const descriptions = [] + } else if (param.oneOf) { + const descriptions: { type: string; description: string }[] = [] for (const childParam of param.oneOf) { paramType.push(childParam.type) - // If there is no parent description, create a description from - // each type if (!param.description) { if (childParam.type === 'array') { if (childParam.items.description) { @@ -164,13 +196,14 @@ export async function getBodyParams(schema, topLevel = false) { if (!param.description) param.description = oneOfDescriptions // This is a workaround for an operation that incorrectly defines anyOf - // for a body parameter. As a workaround, we will use the first object - // in the list of the anyOf array. Otherwise, fallback to the first item - // in the array. There is currently only one occurrence for the operation - // id repos/update-information-about-pages-site. See Ecosystem API issue + // for a body parameter. We use the first object in the list of the anyOf array. + // There is currently only one occurrence for the operation id + // repos/update-information-about-pages-site. See Ecosystem API issue // number #3332 for future plans to fix this in the OpenAPI - } else if (param && param.anyOf && Object.keys(param).length === 1) { - const firstObject = Object.values(param.anyOf).find((item) => item.type === 'object') + } else if (param.anyOf && Object.keys(param).length === 1) { + const firstObject = Object.values(param.anyOf).find( + (item) => (item as Schema).type === 'object', + ) as Schema if (firstObject) { paramType.push('object') param.description = firstObject.description @@ -181,8 +214,8 @@ export async function getBodyParams(schema, topLevel = false) { param.description = param.anyOf[0].description param.isRequired = param.anyOf[0].required } - } else if (param && param.allOf) { - // this else is only used for webhooks handling of allOf + // Used only for webhooks handling allOf + } else if (param.allOf) { for (const prop of param.allOf) { paramType.push('object') childParamsGroups.push(...(await getBodyParams(prop, false))) @@ -200,20 +233,24 @@ export async function getBodyParams(schema, topLevel = false) { return bodyParametersParsed } -async function getTransformedParam(param, paramType, props) { +async function getTransformedParam( + param: Schema, + paramType: string[], + props: BodyParamProps, +): Promise { const { paramKey, required, childParamsGroups, topLevel } = props - const paramDecorated = {} + const paramDecorated: TransformedParam = {} as TransformedParam // Supports backwards compatibility for OpenAPI 3.0 // In 3.1 a nullable type is part of the param.type array and // the property param.nullable does not exist. if (param.nullable) paramType.push('null') paramDecorated.type = Array.from(new Set(paramType.filter(Boolean))).join(' or ') - paramDecorated.name = paramKey + paramDecorated.name = paramKey || '' if (topLevel) { paramDecorated.in = 'body' } - paramDecorated.description = await renderContent(param.description) - if (required && required.includes(paramKey)) { + paramDecorated.description = await renderContent(param.description || '') + if (required && required.includes(paramKey || '')) { paramDecorated.isRequired = true } if (childParamsGroups && childParamsGroups.length > 0 && !param.oneOfObject) { @@ -227,12 +264,12 @@ async function getTransformedParam(param, paramType, props) { obj.name, curr ? (!Object.hasOwn(curr, 'isRequired') ? obj : curr) : obj, ) - }, new Map()) + }, new Map()) .values(), ) paramDecorated.childParamsGroups = mergedChildParamsGroups - } else if (childParamsGroups.length > 0) { + } else if (childParamsGroups && childParamsGroups.length > 0) { paramDecorated.childParamsGroups = childParamsGroups } if (param.enum) { @@ -243,24 +280,28 @@ async function getTransformedParam(param, paramType, props) { paramDecorated.oneOfObject = true } - // we also want to catch default values of `false` for booleans if (param.default !== undefined) { paramDecorated.default = param.default } return paramDecorated } -async function getOneOfChildParams(param) { - const childParamsGroups = [] +async function getOneOfChildParams(param: Schema): Promise { + const childParamsGroups: TransformedParam[] = [] + if (!param.oneOf) { + return childParamsGroups + } for (const oneOfParam of param.oneOf) { - const objParam = { + const objParam: TransformedParam = { type: 'object', name: oneOfParam.title, description: await renderContent(oneOfParam.description), isRequired: oneOfParam.required, childParamsGroups: [], } - objParam.childParamsGroups.push(...(await getBodyParams(oneOfParam, false))) + if (objParam.childParamsGroups) { + objParam.childParamsGroups.push(...(await getBodyParams(oneOfParam, false))) + } childParamsGroups.push(objParam) } return childParamsGroups diff --git a/src/rest/scripts/utils/operation.js b/src/rest/scripts/utils/operation.js index fc67d8907272..e46e93fd07ff 100644 --- a/src/rest/scripts/utils/operation.js +++ b/src/rest/scripts/utils/operation.js @@ -8,7 +8,7 @@ import { renderContent } from '#src/content-render/index.js' import getCodeSamples from './create-rest-examples.js' import operationSchema from './operation-schema.js' import { validateJson } from '#src/tests/lib/validate-json-schema.js' -import { getBodyParams } from './get-body-params.js' +import { getBodyParams } from './get-body-params' export default class Operation { #operation diff --git a/src/rest/scripts/utils/sync.js b/src/rest/scripts/utils/sync.ts similarity index 83% rename from src/rest/scripts/utils/sync.js rename to src/rest/scripts/utils/sync.ts index ed047c578a70..09ddb008f87c 100644 --- a/src/rest/scripts/utils/sync.js +++ b/src/rest/scripts/utils/sync.ts @@ -3,11 +3,15 @@ import { existsSync } from 'fs' import path from 'path' import { mkdirp } from 'mkdirp' -import { updateRestFiles } from './update-markdown.js' -import { allVersions } from '#src/versions/lib/all-versions.js' -import { createOperations, processOperations } from './get-operations.js' -import { getProgAccessData } from '#src/github-apps/scripts/sync.js' -import { REST_DATA_DIR, REST_SCHEMA_FILENAME } from '../../lib/index.js' +import { updateRestFiles } from './update-markdown' +import { allVersions } from '@/versions/lib/all-versions' +import { createOperations, processOperations } from './get-operations' +import { getProgAccessData } from '@/github-apps/scripts/sync' +import { REST_DATA_DIR, REST_SCHEMA_FILENAME } from '../../lib/index' + +type Schema = Record +type Operation = { category: string; subcategory: string; [key: string]: any } +type OperationsByCategory = Record> // All of the schema releases that we store in allVersions // Ex: 'api.github.com', 'ghec', 'ghes-3.6', 'ghes-3.5', @@ -16,13 +20,17 @@ const OPENAPI_VERSION_NAMES = Object.keys(allVersions).map( (elem) => allVersions[elem].openApiVersionName, ) -export async function syncRestData(sourceDirectory, restSchemas, progAccessSource) { +export async function syncRestData( + sourceDirectory: string, + restSchemas: string[], + progAccessSource: string, +): Promise { await Promise.all( restSchemas.map(async (schemaName) => { const file = path.join(sourceDirectory, schemaName) - const schema = JSON.parse(await readFile(file, 'utf-8')) + const schema = JSON.parse(await readFile(file, 'utf-8')) as Schema - const operations = [] + const operations: Operation[] = [] console.log('Instantiating operation instances from schema ', schemaName) try { const newOperations = await createOperations(schema) @@ -62,30 +70,10 @@ export async function syncRestData(sourceDirectory, restSchemas, progAccessSourc await updateRestConfigData(restSchemas) } -/* - Orders the operations by their category and subcategories. - All operations must have a category, but operations don't need - a subcategory. When no subcategory is present, the subcategory - property is an empty string (''). - - Example: - { - [category]: { - '': { - "description": "", - "operations": [] - }, - [subcategory sorted alphabetically]: { - "description": "", - "operations": [] - } - } - } -*/ -async function formatRestData(operations) { +async function formatRestData(operations: Operation[]): Promise { const categories = [...new Set(operations.map((operation) => operation.category))].sort() - const operationsByCategory = {} + const operationsByCategory: OperationsByCategory = {} categories.forEach((category) => { operationsByCategory[category] = {} const categoryOperations = operations.filter((operation) => operation.category === category) @@ -102,7 +90,7 @@ async function formatRestData(operations) { } subcategories.forEach((subcategory) => { - operationsByCategory[category][subcategory] = {} + operationsByCategory[category][subcategory] = [] const subcategoryOperations = categoryOperations.filter( (operation) => operation.subcategory === subcategory, @@ -116,9 +104,12 @@ async function formatRestData(operations) { // Every time we update the REST data files, we'll want to make sure the // config.json file is updated with the latest api versions. -async function updateRestConfigData(schemas) { +async function updateRestConfigData(schemas: string[]): Promise { const restConfigFilename = 'src/rest/lib/config.json' - const restConfigData = JSON.parse(await readFile(restConfigFilename, 'utf8')) + const restConfigData = JSON.parse(await readFile(restConfigFilename, 'utf8')) as Record< + string, + any + > const restApiVersionData = restConfigData['api-versions'] || {} // If the version isn't one of the OpenAPI version, // then it's an api-versioned schema @@ -126,6 +117,9 @@ async function updateRestConfigData(schemas) { const schemaBaseName = path.basename(schema, '.json') if (!OPENAPI_VERSION_NAMES.includes(schemaBaseName)) { const openApiVer = OPENAPI_VERSION_NAMES.find((ver) => schemaBaseName.startsWith(ver)) + if (!openApiVer) { + throw new Error(`Could not find the OpenAPI version for schema ${schemaBaseName}`) + } const date = schemaBaseName.split(`${openApiVer}-`)[1] if (!restApiVersionData[openApiVer]) { @@ -142,9 +136,11 @@ async function updateRestConfigData(schemas) { await writeFile(restConfigFilename, JSON.stringify(restConfigData, null, 2)) } -export async function getOpenApiSchemaFiles(schemas) { - const restSchemas = [] - const webhookSchemas = [] +export async function getOpenApiSchemaFiles( + schemas: string[], +): Promise<{ restSchemas: string[]; webhookSchemas: string[] }> { + const restSchemas: string[] = [] + const webhookSchemas: string[] = [] // The full list of dereferened OpenAPI schemas received from // bundling the OpenAPI in github/github const schemaNames = schemas.map((schema) => path.basename(schema, '.json')) diff --git a/src/rest/tests/get-schema-files.js b/src/rest/tests/get-schema-files.ts similarity index 93% rename from src/rest/tests/get-schema-files.js rename to src/rest/tests/get-schema-files.ts index 5f29d424d0f3..984aac696ba2 100644 --- a/src/rest/tests/get-schema-files.js +++ b/src/rest/tests/get-schema-files.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' -import { getOpenApiSchemaFiles } from '../scripts/utils/sync.js' +import { getOpenApiSchemaFiles } from '../scripts/utils/sync' import { allVersions } from '#src/versions/lib/all-versions.js' const supportedReleases = Object.keys(allVersions).map( diff --git a/src/webhooks/README.md b/src/webhooks/README.md index 5ed567f1b3c6..ca823f0234a2 100644 --- a/src/webhooks/README.md +++ b/src/webhooks/README.md @@ -16,7 +16,7 @@ A [workflow](.github/workflows/sync-openapi.yml) is used to trigger the automati The workflow automatically creates a pull request with the changes (for all three pipelines) and the label `github-openapi-bot`. -The workflow runs the `src/rest/scripts/update-files.js` script, which then calls the `src/webhooks/scripts/sync.js` script. +The workflow runs the `npm run sync-rest` script, which then calls the `src/webhooks/scripts/sync.ts` script. ## Manually running the pipeline @@ -29,7 +29,8 @@ Then, you can manually sync the data used by the REST, Webhooks, and GitHub App To run the webhooks pipeline locally: 1. Clone the [`github/rest-api-description`](https://github.com/github/rest-api-description) repository inside your local `docs-internal` repository. -1. Run `src/rest/scripts/update-files.js -s rest-api-description -o webhooks`. +1. Set a `GITHUB_TOKEN` in your `.env` with (classic) `repo` scopes & enable SSO for the github org. +1. Run `npm run sync-rest -- -s rest-api-description -o webhooks`. ## About this directory @@ -37,7 +38,7 @@ To run the webhooks pipeline locally: - `src/webhooks/lib` - The source code used in production to display the webhook docs and configuration files edited by content and engineering team members. - `src/webhooks/lib/config.json` - A configuration file used to specify metadata about the webhooks pipeline. - `src/webhooks/scripts` - The scripts and source code used run the webhooks pipeline, which updates the `src/webhooks/data` directory. - - `src/webhooks/scripts/sync.js` - The entrypoint script that runs the webhooks pipeline. + - `src/webhooks/scripts/sync.ts` - The entrypoint script that runs the webhooks pipeline. - `src/webhooks/tests` - The tests used to verify the webhooks pipeline. ## Configuring the pipeline diff --git a/src/webhooks/scripts/sync.js b/src/webhooks/scripts/sync.ts similarity index 79% rename from src/webhooks/scripts/sync.js rename to src/webhooks/scripts/sync.ts index c88e59ce353b..77b1480cff39 100644 --- a/src/webhooks/scripts/sync.js +++ b/src/webhooks/scripts/sync.ts @@ -3,14 +3,26 @@ import { existsSync } from 'fs' import path from 'path' import { mkdirp } from 'mkdirp' -import { WEBHOOK_DATA_DIR, WEBHOOK_SCHEMA_FILENAME } from '../lib/index.js' -import Webhook from './webhook.js' +import { WEBHOOK_DATA_DIR, WEBHOOK_SCHEMA_FILENAME } from '../lib/index' +import Webhook, { WebhookSchema } from '@/webhooks/scripts/webhook' -export async function syncWebhookData(sourceDirectory, webhookSchemas) { +interface WebhookFile { + webhooks?: { + post: WebhookSchema + }[] + 'x-webhooks'?: { + post: WebhookSchema + }[] +} + +export async function syncWebhookData( + sourceDirectory: string, + webhookSchemas: string[], +): Promise { await Promise.all( webhookSchemas.map(async (schemaName) => { const file = path.join(sourceDirectory, schemaName) - const schema = JSON.parse(await readFile(file, 'utf-8')) + const schema: WebhookFile = JSON.parse(await readFile(file, 'utf-8')) // In OpenAPI version 3.1, the schema data is under the `webhooks` // key, but in 3.0 the schema data was in `x-webhooks`. // We just fallback to `x-webhooks` for now since there's @@ -47,7 +59,7 @@ export async function syncWebhookData(sourceDirectory, webhookSchemas) { ) } -async function processWebhookSchema(webhooks) { +async function processWebhookSchema(webhooks: Webhook[]): Promise { try { if (webhooks.length) { await Promise.all(webhooks.map((webhook) => webhook.process())) @@ -62,9 +74,11 @@ async function processWebhookSchema(webhooks) { // Create an object with all webhooks where the key is the webhook name. // Webhooks typically have a property called `action` that describes the // events that trigger the webhook. Some webhooks (like `ping`) don't have -// action types -- in that case we set a the value of action to 'default'. -async function formatWebhookData(webhooks) { - const categorizedWebhooks = {} +// action types -- in that case we set the value of action to 'default'. +async function formatWebhookData( + webhooks: Webhook[], +): Promise>> { + const categorizedWebhooks: Record> = {} for (const webhook of Object.values(webhooks)) { if (!webhook.action) webhook.action = 'default' diff --git a/src/webhooks/scripts/webhook-schema.js b/src/webhooks/scripts/webhook-schema.ts similarity index 100% rename from src/webhooks/scripts/webhook-schema.js rename to src/webhooks/scripts/webhook-schema.ts diff --git a/src/webhooks/scripts/webhook.js b/src/webhooks/scripts/webhook.ts similarity index 52% rename from src/webhooks/scripts/webhook.js rename to src/webhooks/scripts/webhook.ts index 59e56a0bc390..f2a334d439d9 100644 --- a/src/webhooks/scripts/webhook.js +++ b/src/webhooks/scripts/webhook.ts @@ -1,10 +1,9 @@ #!/usr/bin/env node import { get, isPlainObject } from 'lodash-es' - -import { getJsonValidator } from '#src/tests/lib/validate-json-schema.js' -import { renderContent } from '#src/content-render/index.js' -import webhookSchema from './webhook-schema.js' -import { getBodyParams } from '../../rest/scripts/utils/get-body-params.js' +import { getJsonValidator } from '@/tests/lib/validate-json-schema' +import { renderContent } from '@/content-render/index' +import webhookSchema from './webhook-schema' +import { getBodyParams, TransformedParam } from '../../rest/scripts/utils/get-body-params' const NO_CHILD_PROPERTIES = [ 'action', @@ -17,13 +16,45 @@ const NO_CHILD_PROPERTIES = [ const validate = getJsonValidator(webhookSchema) -export default class Webhook { - #webhook - constructor(webhook) { +export interface WebhookSchema { + description: string + summary: string + requestBody?: { + content: { + 'application/json': { + schema: Record + } + } + } + 'x-github': { + 'supported-webhook-types': string[] + subcategory: string + } +} + +interface WebhookInterface { + descriptionHtml: string + summaryHtml: string + bodyParameters: TransformedParam[] + availability: string[] + action: string | null + category: string + process(): Promise + renderDescription(): Promise + renderBodyParameterDescriptions(): Promise +} + +export default class Webhook implements WebhookInterface { + #webhook: WebhookSchema + descriptionHtml: string = '' + summaryHtml: string = '' + bodyParameters: TransformedParam[] = [] + availability: string[] + action: string | null + category: string + + constructor(webhook: WebhookSchema) { this.#webhook = webhook - this.descriptionHtml = '' - this.summaryHtml = '' - this.bodyParameters = [] this.availability = webhook['x-github']['supported-webhook-types'] this.action = get( webhook, @@ -45,30 +76,29 @@ export default class Webhook { // The OpenAPI uses hyphens for the webhook names, but the webhooks // are sent using underscores (e.g. `branch_protection_rule` instead // of `branch-protection-rule`) - this.category = webhook['x-github'].subcategory.replaceAll('-', '_') - return this + this.category = webhook['x-github'].subcategory.replace(/-/g, '_') } - async process() { + async process(): Promise { await Promise.all([this.renderDescription(), this.renderBodyParameterDescriptions()]) - const isValid = validate(this) + const isValid = validate(this as WebhookInterface) // Add type assertion here if (!isValid) { console.error(JSON.stringify(validate.errors, null, 2)) throw new Error(`Invalid OpenAPI webhook found: ${this.category}`) } } - async renderDescription() { + async renderDescription(): Promise { this.descriptionHtml = await renderContent(this.#webhook.description) this.summaryHtml = await renderContent(this.#webhook.summary) return this } - async renderBodyParameterDescriptions() { - if (!this.#webhook.requestBody) return [] - const schema = get(this.#webhook, `requestBody.content.['application/json'].schema`, {}) - this.bodyParameters = isPlainObject(schema) ? await getBodyParams(schema, true, this.title) : [] + async renderBodyParameterDescriptions(): Promise { + if (!this.#webhook.requestBody) return + const schema = get(this.#webhook, `requestBody.content['application/json'].schema`, {}) + this.bodyParameters = isPlainObject(schema) ? await getBodyParams(schema, true) : [] // Removes the children of the common properties this.bodyParameters.forEach((param) => { diff --git a/src/webhooks/tests/get-schema-files.js b/src/webhooks/tests/get-schema-files.ts similarity index 98% rename from src/webhooks/tests/get-schema-files.js rename to src/webhooks/tests/get-schema-files.ts index 164b5ebeb023..06f09174a400 100644 --- a/src/webhooks/tests/get-schema-files.js +++ b/src/webhooks/tests/get-schema-files.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'vitest' -import { getOpenApiSchemaFiles } from '../../rest/scripts/utils/sync.js' +import { getOpenApiSchemaFiles } from '../../rest/scripts/utils/sync' import { allVersions } from '#src/versions/lib/all-versions.js' describe('webhook data files are generated correctly from dereferenced openapi files', () => {