diff --git a/CHANGELOG.md b/CHANGELOG.md index 67d797bfec26..9456f8657a11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Docs changelog +**16 July 2025** + +We've added documentation describing how to use the GraphQL API to create a new issue and, in the same request, assign the issue to Copilot coding agent. + +See: [Using Copilot to work on an issue](https://docs.github.com/copilot/how-tos/agents/copilot-coding-agent/using-copilot-to-work-on-an-issue#assigning-an-issue-to-copilot-via-the-github-api). + +
+ +**16 July 2025** + +We've updated the Copilot documentation to coincide with the release of an improved user interface for configuring the firewall for Copilot coding agent. + +See: [Customizing or disabling the firewall for Copilot coding agent](https://docs.github.com/en/copilot/how-tos/agents/copilot-coding-agent/customizing-or-disabling-the-firewall-for-copilot-coding-agent). + +
+ +**16 July 2025** + +We've updated the Copilot docs to coincide with the release of issue form support for Copilot Chat. When you use Copilot Chat to create an issue, an issue form will be used if there's an appropriate one in the repo. Previously only issue templates were supported. + +See [Using GitHub Copilot to create issues](https://docs.github.com/copilot/how-tos/github-flow/using-github-copilot-to-create-issues). + +
+ **30 June 2025** Many enterprise customers want to measure the downstream impact of Copilot on their company, looking beyond leading metrics like adoption and usage. diff --git a/content/actions/concepts/runners/about-actions-runner-controller.md b/content/actions/concepts/runners/about-actions-runner-controller.md index 02a778de4696..621039631040 100644 --- a/content/actions/concepts/runners/about-actions-runner-controller.md +++ b/content/actions/concepts/runners/about-actions-runner-controller.md @@ -13,8 +13,6 @@ redirect_from: - /actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/about-actions-runner-controller --- -[Legal notice](#legal-notice) - ## About {% data variables.product.prodname_actions_runner_controller %} {% data reusables.actions.actions-runner-controller-about-arc %} diff --git a/content/actions/concepts/runners/about-runner-scale-sets.md b/content/actions/concepts/runners/about-runner-scale-sets.md index 5af04b7443c7..bbd45b54cdc2 100644 --- a/content/actions/concepts/runners/about-runner-scale-sets.md +++ b/content/actions/concepts/runners/about-runner-scale-sets.md @@ -12,8 +12,6 @@ topics: - Actions Runner Controller --- -[Legal notice](#legal-notice) - ## About runner scale sets A runner scale set is a group of homogeneous runners that can be assigned jobs from {% data variables.product.prodname_actions %}. The number of active runners owned by a runner scale set can be controlled by auto-scaling runner solutions such as {% data variables.product.prodname_actions_runner_controller %} (ARC). diff --git a/content/actions/how-tos/sharing-automations/creating-workflow-templates-for-your-organization.md b/content/actions/how-tos/sharing-automations/creating-workflow-templates-for-your-organization.md index e27b13bfb98b..dd33b188f63c 100644 --- a/content/actions/how-tos/sharing-automations/creating-workflow-templates-for-your-organization.md +++ b/content/actions/how-tos/sharing-automations/creating-workflow-templates-for-your-organization.md @@ -16,29 +16,14 @@ type: tutorial topics: - Workflows - CI +permissions: Write access to the organization's public `.github` repository. Templates can be used by organization members who have permission to create workflows. --- {% data reusables.actions.enterprise-github-hosted-runners %} -## Overview - -{% data reusables.actions.workflow-organization-templates %} - -{% data reusables.actions.workflow-templates-categories %} - -> [!NOTE] -> Because workflow templates require a public `.github` repository, they are not available for {% data variables.product.prodname_emus %}. - -## Creating a workflow template - -Workflow templates can be created by users with write access to the organization's _public_ `.github` repository. These can then be used by organization members who have permission to create workflows. - -{% ifversion fpt %} -Workflow templates created by users can only be used to create workflows in public repositories. Organizations using {% data variables.product.prodname_ghe_cloud %} can also use workflow templates to create workflows in private repositories. For more information, see the [{% data variables.product.prodname_ghe_cloud %} documentation](/enterprise-cloud@latest/actions/using-workflows/creating-starter-workflows-for-your-organization). -{% endif %} - > [!NOTE] -> To avoid duplication among workflow templates you can call reusable workflows from within a workflow. This can help make your workflows easier to maintain. For more information, see [AUTOTITLE](/actions/using-workflows/reusing-workflows). +> * Because workflow templates require a public `.github` repository, they are not available for {% data variables.product.prodname_emus %}. +> * To avoid duplication among workflow templates you can call reusable workflows from within a workflow. This can help make your workflows easier to maintain. For more information, see [AUTOTITLE](/actions/using-workflows/reusing-workflows). This procedure demonstrates how to create a workflow template and metadata file. The metadata file describes how the workflow templates will be presented to users when they are creating a new workflow. diff --git a/content/actions/reference/extending-github-actions-importer-with-custom-transformers.md b/content/actions/reference/extending-github-actions-importer-with-custom-transformers.md index b926bc144b37..28c82d2ce6d3 100644 --- a/content/actions/reference/extending-github-actions-importer-with-custom-transformers.md +++ b/content/actions/reference/extending-github-actions-importer-with-custom-transformers.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/extending-github-actions-importer-with-custom-transformers --- -[Legal notice](#legal-notice) - ## About custom transformers {% data variables.product.prodname_actions_importer %} offers the ability to extend its built-in mapping by creating custom transformers. Custom transformers can be used to: diff --git a/content/actions/reference/supplemental-arguments-and-settings.md b/content/actions/reference/supplemental-arguments-and-settings.md index 6872160add52..c8d2f4dce080 100644 --- a/content/actions/reference/supplemental-arguments-and-settings.md +++ b/content/actions/reference/supplemental-arguments-and-settings.md @@ -15,8 +15,6 @@ redirect_from: - /actions/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/supplemental-arguments-and-settings --- -[Legal notice](#legal-notice) - This article provides general information for configuring {% data variables.product.prodname_actions_importer %}'s supplemental arguments and settings, such as optional parameters, path arguments, and network settings. ## Optional parameters diff --git a/content/actions/tutorials/actions-runner-controller/authenticating-arc-to-the-github-api.md b/content/actions/tutorials/actions-runner-controller/authenticating-arc-to-the-github-api.md index 43eeb8dc3fcb..83b32ad3c14f 100644 --- a/content/actions/tutorials/actions-runner-controller/authenticating-arc-to-the-github-api.md +++ b/content/actions/tutorials/actions-runner-controller/authenticating-arc-to-the-github-api.md @@ -15,8 +15,6 @@ redirect_from: - /actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/authenticating-to-the-github-api#deploying-using-personal-access-token-classic-authentication --- -[Legal notice](#legal-notice) - You can authenticate {% data variables.product.prodname_actions_runner_controller %} (ARC) to the {% data variables.product.prodname_dotcom %} API by using a {% data variables.product.prodname_github_app %} or by using a {% data variables.product.pat_v1 %}. > [!NOTE] diff --git a/content/actions/tutorials/actions-runner-controller/deploying-runner-scale-sets-with-actions-runner-controller.md b/content/actions/tutorials/actions-runner-controller/deploying-runner-scale-sets-with-actions-runner-controller.md index bab7c04c57cd..ddeb091bdcb9 100644 --- a/content/actions/tutorials/actions-runner-controller/deploying-runner-scale-sets-with-actions-runner-controller.md +++ b/content/actions/tutorials/actions-runner-controller/deploying-runner-scale-sets-with-actions-runner-controller.md @@ -15,8 +15,6 @@ redirect_from: - /actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/deploying-runner-scale-sets-with-actions-runner-controller --- -[Legal notice](#legal-notice) - ## Deploying a runner scale set To deploy a runner scale set, you must have ARC up and running. For more information, see [AUTOTITLE](/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/quickstart-for-actions-runner-controller). diff --git a/content/actions/tutorials/actions-runner-controller/quickstart-for-actions-runner-controller.md b/content/actions/tutorials/actions-runner-controller/quickstart-for-actions-runner-controller.md index d5f1b7b38d62..d89028dd7d79 100644 --- a/content/actions/tutorials/actions-runner-controller/quickstart-for-actions-runner-controller.md +++ b/content/actions/tutorials/actions-runner-controller/quickstart-for-actions-runner-controller.md @@ -15,14 +15,6 @@ redirect_from: - /actions/tutorials/quickstart-for-actions-runner-controller --- -[Legal notice](#legal-notice) - -## Introduction - -{% data reusables.actions.actions-runner-controller-about-arc %} - -You can set up ARC on Kubernetes using Helm, then create and run a workflow that uses runner scale sets. For more information about runner scale sets, see [AUTOTITLE](/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/deploying-runner-scale-sets-with-actions-runner-controller#runner-scale-set). - ## Prerequisites In order to use ARC, ensure you have the following. diff --git a/content/actions/tutorials/actions-runner-controller/troubleshooting-actions-runner-controller-errors.md b/content/actions/tutorials/actions-runner-controller/troubleshooting-actions-runner-controller-errors.md index 870a8d9a953f..8a8ecd86aaf9 100644 --- a/content/actions/tutorials/actions-runner-controller/troubleshooting-actions-runner-controller-errors.md +++ b/content/actions/tutorials/actions-runner-controller/troubleshooting-actions-runner-controller-errors.md @@ -14,8 +14,6 @@ redirect_from: - /actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/troubleshooting-actions-runner-controller-errors --- -[Legal notice](#legal-notice) - ## Logging The {% data variables.product.prodname_actions_runner_controller %} (ARC) resources, which include the controller, listener, and runners, write logs to standard output (`stdout`). We recommend you implement a logging solution to collect and store these logs. Having logs available can help you or GitHub support with troubleshooting and debugging. For more information, see [Logging Architecture](https://kubernetes.io/docs/concepts/cluster-administration/logging/) in the Kubernetes documentation. diff --git a/content/actions/tutorials/actions-runner-controller/using-actions-runner-controller-runners-in-a-workflow.md b/content/actions/tutorials/actions-runner-controller/using-actions-runner-controller-runners-in-a-workflow.md index c884099800b1..ed9a02d58123 100644 --- a/content/actions/tutorials/actions-runner-controller/using-actions-runner-controller-runners-in-a-workflow.md +++ b/content/actions/tutorials/actions-runner-controller/using-actions-runner-controller-runners-in-a-workflow.md @@ -15,8 +15,6 @@ redirect_from: - /actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/using-actions-runner-controller-runners-in-a-workflow --- -[Legal notice](#legal-notice) - ## Using ARC runners in a workflow file To assign jobs to run on a runner scale set, you can specify the name of the scale set as the value for the `runs-on` key in your {% data variables.product.prodname_actions %} workflow file. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/automating-migration-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/automating-migration-with-github-actions-importer.md index 066b7990dc9e..aaf77047a053 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/automating-migration-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/automating-migration-with-github-actions-importer.md @@ -20,8 +20,6 @@ shortTitle: 'Automate migration with {% data variables.product.prodname_actions_ {% data reusables.actions.enterprise-github-hosted-runners %} -[Legal notice](#legal-notice) - ## About {% data variables.product.prodname_actions_importer %} You can use {% data variables.product.prodname_actions_importer %} to plan and automatically migrate your CI/CD supported pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-azure-devops-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-azure-devops-with-github-actions-importer.md index a5dd64bb7d2e..8db96c5c7b35 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-azure-devops-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-azure-devops-with-github-actions-importer.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-azure-devops-with-github-actions-importer --- -[Legal notice](#legal-notice) - ## About migrating from Azure DevOps with GitHub Actions Importer The instructions below will guide you through configuring your environment to use {% data variables.product.prodname_actions_importer %} to migrate Azure DevOps pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bamboo-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bamboo-with-github-actions-importer.md index cc01d83f1dea..43a1056b834a 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bamboo-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bamboo-with-github-actions-importer.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bamboo-with-github-actions-importer --- -[Legal notice](#legal-notice) - ## About migrating from Bamboo with GitHub Actions Importer The instructions below will guide you through configuring your environment to use {% data variables.product.prodname_actions_importer %} to migrate Bamboo pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bitbucket-pipelines-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bitbucket-pipelines-with-github-actions-importer.md index 61bedbaa2227..95413213d253 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bitbucket-pipelines-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bitbucket-pipelines-with-github-actions-importer.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-bitbucket-pipelines-with-github-actions-importer --- -[Legal notice](#legal-notice) - ## About migrating from Bitbucket Pipelines with GitHub Actions Importer The instructions below will guide you through configuring your environment to use {% data variables.product.prodname_actions_importer %} to migrate Bitbucket Pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-circleci-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-circleci-with-github-actions-importer.md index edc1132485b6..dccd734fb0eb 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-circleci-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-circleci-with-github-actions-importer.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-circleci-with-github-actions-importer --- -[Legal notice](#legal-notice) - ## About migrating from CircleCI with GitHub Actions Importer The instructions below will guide you through configuring your environment to use {% data variables.product.prodname_actions_importer %} to migrate CircleCI pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-gitlab-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-gitlab-with-github-actions-importer.md index 839e12de8c7c..21a95eb43937 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-gitlab-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-gitlab-with-github-actions-importer.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-gitlab-with-github-actions-importer --- -[Legal notice](#legal-notice) - ## About migrating from GitLab with GitHub Actions Importer The instructions below will guide you through configuring your environment to use {% data variables.product.prodname_actions_importer %} to migrate GitLab pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-jenkins-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-jenkins-with-github-actions-importer.md index 94954c6a0e3d..c50a5db437f8 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-jenkins-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-jenkins-with-github-actions-importer.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-jenkins-with-github-actions-importer --- -[Legal notice](#legal-notice) - ## About migrating from Jenkins with GitHub Actions Importer The instructions below will guide you through configuring your environment to use {% data variables.product.prodname_actions_importer %} to migrate Jenkins pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-travis-ci-with-github-actions-importer.md b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-travis-ci-with-github-actions-importer.md index 696a2efb51be..8155fac04c6a 100644 --- a/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-travis-ci-with-github-actions-importer.md +++ b/content/actions/tutorials/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-travis-ci-with-github-actions-importer.md @@ -17,8 +17,6 @@ redirect_from: - /actions/how-tos/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-travis-ci-with-github-actions-importer --- -[Legal notice](#legal-notice) - ## About migrating from Travis CI with GitHub Actions Importer The instructions below will guide you through configuring your environment to use {% data variables.product.prodname_actions_importer %} to migrate Travis CI pipelines to {% data variables.product.prodname_actions %}. diff --git a/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-repository-management-policies-in-your-enterprise.md b/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-repository-management-policies-in-your-enterprise.md index da2e89b24927..258183468535 100644 --- a/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-repository-management-policies-in-your-enterprise.md +++ b/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-repository-management-policies-in-your-enterprise.md @@ -80,6 +80,9 @@ Across all organizations owned by your enterprise, you can set a base repository 1. Under "Base permissions", review the information about changing the setting. {% data reusables.enterprise-accounts.view-current-policy-config-orgs %} 1. Under "Base permissions", select the dropdown menu and click a policy. +> [!NOTE] +> Internal repositories have a minimum visibility level of read, even if the base permission has been set to none. + ## Enforcing a policy for repository creation Across all organizations owned by your enterprise, you can allow members to create repositories, restrict repository creation to organization owners, or allow owners to administer the setting on the organization level. diff --git a/content/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/setting-base-permissions-for-an-organization.md b/content/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/setting-base-permissions-for-an-organization.md index f94b067e809e..e3b0f9e5c269 100644 --- a/content/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/setting-base-permissions-for-an-organization.md +++ b/content/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/setting-base-permissions-for-an-organization.md @@ -31,6 +31,7 @@ If you've created a custom repository role with an inherited role that is lower > [!NOTE] > * All changes to base permissions will affect both new and existing members. > * {% data reusables.repositories.org-base-permissions-private-forks %} +> * Internal repositories have a minimum visibility level of read, even if the base permission has been set to none. ## Setting base permissions diff --git a/src/rest/scripts/utils/get-body-params.ts b/src/rest/scripts/utils/get-body-params.ts index b4f09efb9db2..e5ca3030b9e7 100644 --- a/src/rest/scripts/utils/get-body-params.ts +++ b/src/rest/scripts/utils/get-body-params.ts @@ -74,6 +74,19 @@ async function getTopLevelOneOfProperty( } // Gets the body parameters for a given schema recursively. +// Helper function to handle oneOf fields where all items are objects +async function handleObjectOnlyOneOf( + param: Schema, + paramType: string[], +): Promise { + if (param.oneOf && param.oneOf.every((object: TransformedParam) => object.type === 'object')) { + paramType.push('object') + param.oneOfObject = true + return await getOneOfChildParams(param) + } + return [] +} + export async function getBodyParams(schema: Schema, topLevel = false): Promise { const bodyParametersParsed: TransformedParam[] = [] const schemaObject = schema.oneOf && topLevel ? await getTopLevelOneOfProperty(schema) : schema @@ -161,38 +174,45 @@ export async function getBodyParams(schema: Schema, topLevel = false): Promise object.type === 'object')) { - param.oneOfObject = true - childParamsGroups.push(...(await getOneOfChildParams(param))) + const oneOfChildren = await handleObjectOnlyOneOf(param, paramType) + if (oneOfChildren.length > 0) { + childParamsGroups.push(...oneOfChildren) } } else { childParamsGroups.push(...(await getBodyParams(param, false))) } } else if (param.oneOf) { - const descriptions: { type: string; description: string }[] = [] - for (const childParam of param.oneOf) { - paramType.push(childParam.type) - if (!param.description) { - if (childParam.type === 'array') { - if (childParam.items.description) { - descriptions.push({ - type: childParam.type, - description: childParam.items.description, - }) + // Check if all oneOf items are objects - if so, treat this as a oneOfObject case + const oneOfChildren = await handleObjectOnlyOneOf(param, paramType) + if (oneOfChildren.length > 0) { + childParamsGroups.push(...oneOfChildren) + } else { + // Handle mixed types or non-object oneOf cases + const descriptions: { type: string; description: string }[] = [] + for (const childParam of param.oneOf) { + paramType.push(childParam.type) + if (!param.description) { + if (childParam.type === 'array') { + if (childParam.items.description) { + descriptions.push({ + type: childParam.type, + description: childParam.items.description, + }) + } + } else { + if (childParam.description) { + descriptions.push({ type: childParam.type, description: childParam.description }) + } } } else { - if (childParam.description) { - descriptions.push({ type: childParam.type, description: childParam.description }) - } + descriptions.push({ type: param.type, description: param.description }) } - } else { - descriptions.push({ type: param.type, description: param.description }) } + // Occasionally, there is no parent description and the description + // is in the first child parameter. + const oneOfDescriptions = descriptions.length ? descriptions[0].description : '' + if (!param.description) param.description = oneOfDescriptions } - // Occasionally, there is no parent description and the description - // is in the first child parameter. - const oneOfDescriptions = descriptions.length ? descriptions[0].description : '' - if (!param.description) param.description = oneOfDescriptions // This is a workaround for an operation that incorrectly defines anyOf // for a body parameter. We use the first object in the list of the anyOf array. diff --git a/src/webhooks/tests/oneof-handling.js b/src/webhooks/tests/oneof-handling.js new file mode 100644 index 000000000000..41a28826ef1d --- /dev/null +++ b/src/webhooks/tests/oneof-handling.js @@ -0,0 +1,268 @@ +import { describe, expect, test } from 'vitest' +import { getBodyParams } from '../../rest/scripts/utils/get-body-params' + +describe('oneOf handling in webhook parameters', () => { + test('should handle oneOf fields correctly for secret_scanning_alert_location details', async () => { + // Mock schema representing the secret_scanning_alert_location details field + // This simulates the structure found in the actual OpenAPI schema + const mockSchema = { + type: 'object', + properties: { + location: { + type: 'object', + properties: { + type: { + type: 'string', + description: + 'The location type. Because secrets may be found in different types of resources (ie. code, comments, issues, pull requests, discussions), this field identifies the type of resource where the secret was found.', + enum: [ + 'commit', + 'wiki_commit', + 'issue_title', + 'issue_body', + 'issue_comment', + 'discussion_title', + 'discussion_body', + 'discussion_comment', + 'pull_request_title', + 'pull_request_body', + 'pull_request_comment', + 'pull_request_review', + 'pull_request_review_comment', + ], + }, + details: { + oneOf: [ + { + type: 'object', + title: 'commit', + description: + "Represents a 'commit' secret scanning location type. This location type shows that a secret was detected inside a commit to a repository.", + properties: { + path: { + type: 'string', + description: 'The file path in the repository', + }, + start_line: { + type: 'integer', + description: 'Line number at which the secret starts in the file', + }, + end_line: { + type: 'integer', + description: 'Line number at which the secret ends in the file', + }, + start_column: { + type: 'integer', + description: + 'The column at which the secret starts within the start line when the file is interpreted as 8BIT ASCII', + }, + end_column: { + type: 'integer', + description: + 'The column at which the secret ends within the end line when the file is interpreted as 8BIT ASCII', + }, + blob_sha: { + type: 'string', + description: 'SHA-1 hash ID of the associated blob', + }, + blob_url: { + type: 'string', + description: 'The API URL to get the associated blob resource', + }, + commit_sha: { + type: 'string', + description: 'SHA-1 hash ID of the associated commit', + }, + commit_url: { + type: 'string', + description: 'The API URL to get the associated commit resource', + }, + }, + }, + { + type: 'object', + title: 'issue_title', + description: + "Represents an 'issue_title' secret scanning location type. This location type shows that a secret was detected in the title of an issue.", + properties: { + issue_title_url: { + type: 'string', + description: 'The API URL to get the associated issue resource', + }, + }, + }, + { + type: 'object', + title: 'issue_body', + description: + "Represents an 'issue_body' secret scanning location type. This location type shows that a secret was detected in the body of an issue.", + properties: { + issue_body_url: { + type: 'string', + description: 'The API URL to get the associated issue resource', + }, + }, + }, + { + type: 'object', + title: 'issue_comment', + description: + "Represents an 'issue_comment' secret scanning location type. This location type shows that a secret was detected in a comment on an issue.", + properties: { + issue_comment_url: { + type: 'string', + description: 'The API URL to get the associated issue comment resource', + }, + }, + }, + ], + }, + }, + }, + }, + } + + const result = await getBodyParams(mockSchema, true) + + // Find the location parameter + const locationParam = result.find((param) => param.name === 'location') + expect(locationParam).toBeDefined() + expect(locationParam?.childParamsGroups).toBeDefined() + + // Find the details parameter within location + const detailsParam = locationParam?.childParamsGroups?.find((param) => param.name === 'details') + expect(detailsParam).toBeDefined() + expect(detailsParam?.type).toBe('object') + + // Verify that oneOf handling created multiple child param groups + expect(detailsParam?.childParamsGroups).toBeDefined() + expect(detailsParam?.childParamsGroups?.length).toBeGreaterThan(1) + + // Check that we have the expected oneOf objects + const childParams = detailsParam?.childParamsGroups || [] + const commitParam = childParams.find((param) => param.name === 'commit') + const issueTitleParam = childParams.find((param) => param.name === 'issue_title') + const issueBodyParam = childParams.find((param) => param.name === 'issue_body') + const issueCommentParam = childParams.find((param) => param.name === 'issue_comment') + + expect(commitParam).toBeDefined() + expect(commitParam?.description).toContain("commit' secret scanning location type") + expect(commitParam?.childParamsGroups?.length).toBeGreaterThan(0) + + expect(issueTitleParam).toBeDefined() + expect(issueTitleParam?.description).toContain("issue_title' secret scanning location type") + + expect(issueBodyParam).toBeDefined() + expect(issueBodyParam?.description).toContain("issue_body' secret scanning location type") + + expect(issueCommentParam).toBeDefined() + expect(issueCommentParam?.description).toContain("issue_comment' secret scanning location type") + + // Verify that the oneOfObject flag is set + expect(detailsParam?.oneOfObject).toBe(true) + }) + + test('should handle oneOf fields with missing titles gracefully', async () => { + const mockSchemaWithoutTitles = { + type: 'object', + properties: { + details: { + oneOf: [ + { + type: 'object', + description: 'First option without title', + properties: { + field1: { + type: 'string', + description: 'Field 1', + }, + }, + }, + { + type: 'object', + description: 'Second option without title', + properties: { + field2: { + type: 'string', + description: 'Field 2', + }, + }, + }, + ], + }, + }, + } + + const result = await getBodyParams(mockSchemaWithoutTitles, true) + + const detailsParam = result.find((param) => param.name === 'details') + expect(detailsParam).toBeDefined() + expect(detailsParam?.childParamsGroups?.length).toBe(2) + + // When titles are missing, the name should be undefined or handled gracefully + detailsParam?.childParamsGroups?.forEach((param) => { + expect(param.type).toBe('object') + expect(param.description).toBeDefined() + }) + }) + + test('should handle nested oneOf correctly', async () => { + const mockNestedOneOfSchema = { + type: 'object', + properties: { + wrapper: { + type: 'object', + properties: { + inner: { + oneOf: [ + { + type: 'object', + title: 'option_a', + description: 'Option A description', + properties: { + field_a: { + type: 'string', + description: 'Field A', + }, + }, + }, + { + type: 'object', + title: 'option_b', + description: 'Option B description', + properties: { + field_b: { + type: 'string', + description: 'Field B', + }, + }, + }, + ], + }, + }, + }, + }, + } + + const result = await getBodyParams(mockNestedOneOfSchema, true) + + const wrapperParam = result.find((param) => param.name === 'wrapper') + expect(wrapperParam).toBeDefined() + + const innerParam = wrapperParam?.childParamsGroups?.find((param) => param.name === 'inner') + expect(innerParam).toBeDefined() + expect(innerParam?.oneOfObject).toBe(true) + expect(innerParam?.childParamsGroups?.length).toBe(2) + + const optionA = innerParam?.childParamsGroups?.find((param) => param.name === 'option_a') + const optionB = innerParam?.childParamsGroups?.find((param) => param.name === 'option_b') + + expect(optionA).toBeDefined() + expect(optionA?.description).toContain('Option A description') + expect(optionA?.childParamsGroups?.length).toBe(1) + + expect(optionB).toBeDefined() + expect(optionB?.description).toContain('Option B description') + expect(optionB?.childParamsGroups?.length).toBe(1) + }) +}) diff --git a/src/webhooks/tests/webhook-generation-oneof.js b/src/webhooks/tests/webhook-generation-oneof.js new file mode 100644 index 000000000000..b7ff4534c208 --- /dev/null +++ b/src/webhooks/tests/webhook-generation-oneof.js @@ -0,0 +1,428 @@ +import { describe, expect, test } from 'vitest' +import Webhook from '../scripts/webhook' + +describe('webhook generation with oneOf fields', () => { + test('should properly generate webhook documentation for secret_scanning_alert_location with oneOf details', async () => { + // Mock OpenAPI schema that represents the actual structure from github/rest-api-description + // This simulates the secret_scanning_alert_location webhook with oneOf details field + const mockWebhookSchema = { + summary: + 'This event occurs when there is activity relating to the locations of a secret in a secret scanning alert.', + description: + 'A new instance of a previously detected secret was detected in a repository, and the location of the secret was added to the existing alert.', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + action: { + type: 'string', + enum: ['created'], + }, + alert: { + type: 'object', + properties: { + number: { + type: 'integer', + description: 'The security alert number.', + }, + created_at: { + type: 'string', + description: + 'The time that the alert was created in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ.', + }, + }, + }, + location: { + type: 'object', + properties: { + type: { + type: 'string', + description: + 'The location type. Because secrets may be found in different types of resources (ie. code, comments, issues, pull requests, discussions), this field identifies the type of resource where the secret was found.', + enum: [ + 'commit', + 'wiki_commit', + 'issue_title', + 'issue_body', + 'issue_comment', + 'discussion_title', + 'discussion_body', + 'discussion_comment', + 'pull_request_title', + 'pull_request_body', + 'pull_request_comment', + 'pull_request_review', + 'pull_request_review_comment', + ], + }, + details: { + oneOf: [ + { + title: 'commit', + type: 'object', + description: + "Represents a 'commit' secret scanning location type. This location type shows that a secret was detected inside a commit to a repository.", + properties: { + path: { + type: 'string', + description: 'The file path in the repository', + }, + start_line: { + type: 'integer', + description: 'Line number at which the secret starts in the file', + }, + end_line: { + type: 'integer', + description: 'Line number at which the secret ends in the file', + }, + start_column: { + type: 'integer', + description: + 'The column at which the secret starts within the start line when the file is interpreted as 8BIT ASCII', + }, + end_column: { + type: 'integer', + description: + 'The column at which the secret ends within the end line when the file is interpreted as 8BIT ASCII', + }, + blob_sha: { + type: 'string', + description: 'SHA-1 hash ID of the associated blob', + }, + blob_url: { + type: 'string', + description: 'The API URL to get the associated blob resource', + }, + commit_sha: { + type: 'string', + description: 'SHA-1 hash ID of the associated commit', + }, + commit_url: { + type: 'string', + description: 'The API URL to get the associated commit resource', + }, + }, + }, + { + title: 'issue_title', + type: 'object', + description: + "Represents an 'issue_title' secret scanning location type. This location type shows that a secret was detected in the title of an issue.", + properties: { + issue_title_url: { + type: 'string', + description: 'The API URL to get the associated issue resource', + }, + }, + }, + { + title: 'issue_body', + type: 'object', + description: + "Represents an 'issue_body' secret scanning location type. This location type shows that a secret was detected in the body of an issue.", + properties: { + issue_body_url: { + type: 'string', + description: 'The API URL to get the associated issue resource', + }, + }, + }, + { + title: 'issue_comment', + type: 'object', + description: + "Represents an 'issue_comment' secret scanning location type. This location type shows that a secret was detected in a comment on an issue.", + properties: { + issue_comment_url: { + type: 'string', + description: + 'The API URL to get the associated issue comment resource', + }, + }, + }, + { + title: 'discussion_title', + type: 'object', + description: + "Represents a 'discussion_title' secret scanning location type. This location type shows that a secret was detected in the title of a discussion.", + properties: { + discussion_title_url: { + type: 'string', + description: 'The API URL to get the associated discussion resource', + }, + }, + }, + { + title: 'discussion_body', + type: 'object', + description: + "Represents a 'discussion_body' secret scanning location type. This location type shows that a secret was detected in the body of a discussion.", + properties: { + discussion_body_url: { + type: 'string', + description: 'The API URL to get the associated discussion resource', + }, + }, + }, + { + title: 'discussion_comment', + type: 'object', + description: + "Represents a 'discussion_comment' secret scanning location type. This location type shows that a secret was detected in a comment on a discussion.", + properties: { + discussion_comment_url: { + type: 'string', + description: + 'The API URL to get the associated discussion comment resource', + }, + }, + }, + { + title: 'pull_request_title', + type: 'object', + description: + "Represents a 'pull_request_title' secret scanning location type. This location type shows that a secret was detected in the title of a pull request.", + properties: { + pull_request_title_url: { + type: 'string', + description: + 'The API URL to get the associated pull request resource', + }, + }, + }, + { + title: 'pull_request_body', + type: 'object', + description: + "Represents a 'pull_request_body' secret scanning location type. This location type shows that a secret was detected in the body of a pull request.", + properties: { + pull_request_body_url: { + type: 'string', + description: + 'The API URL to get the associated pull request resource', + }, + }, + }, + { + title: 'pull_request_comment', + type: 'object', + description: + "Represents a 'pull_request_comment' secret scanning location type. This location type shows that a secret was detected in a comment on a pull request.", + properties: { + pull_request_comment_url: { + type: 'string', + description: + 'The API URL to get the associated pull request comment resource', + }, + }, + }, + { + title: 'pull_request_review', + type: 'object', + description: + "Represents a 'pull_request_review' secret scanning location type. This location type shows that a secret was detected in a pull request review.", + properties: { + pull_request_review_url: { + type: 'string', + description: + 'The API URL to get the associated pull request review resource', + }, + }, + }, + { + title: 'pull_request_review_comment', + type: 'object', + description: + "Represents a 'pull_request_review_comment' secret scanning location type. This location type shows that a secret was detected in a comment on a pull request review.", + properties: { + pull_request_review_comment_url: { + type: 'string', + description: + 'The API URL to get the associated pull request review comment resource', + }, + }, + }, + ], + }, + }, + }, + repository: { + type: 'object', + description: 'The repository on GitHub where the event occurred.', + }, + sender: { + type: 'object', + description: 'A GitHub user.', + }, + }, + }, + }, + }, + }, + 'x-github': { + 'supported-webhook-types': ['repository', 'organization', 'app'], + subcategory: 'secret_scanning_alert_location', + }, + } + + // Create webhook instance and process it + const webhook = new Webhook(mockWebhookSchema) + await webhook.process() + + // Verify basic webhook properties + expect(webhook.category).toBe('secret_scanning_alert_location') + expect(webhook.action).toBe('created') + expect(webhook.availability).toEqual(['repository', 'organization', 'app']) + expect(webhook.bodyParameters).toBeDefined() + expect(webhook.bodyParameters.length).toBeGreaterThan(0) + + // Find the location parameter + const locationParam = webhook.bodyParameters.find((param) => param.name === 'location') + expect(locationParam).toBeDefined() + expect(locationParam?.type).toBe('object') + expect(locationParam?.childParamsGroups).toBeDefined() + + // Find the details parameter within location + const detailsParam = locationParam?.childParamsGroups?.find((param) => param.name === 'details') + expect(detailsParam).toBeDefined() + expect(detailsParam?.type).toBe('object') + + // Verify that oneOf handling worked correctly + expect(detailsParam?.oneOfObject).toBe(true) + expect(detailsParam?.childParamsGroups).toBeDefined() + expect(detailsParam?.childParamsGroups?.length).toBeGreaterThan(1) + + // Check that all expected oneOf variants are present + const childParams = detailsParam?.childParamsGroups || [] + const variantNames = childParams.map((param) => param.name) + + expect(variantNames).toContain('commit') + expect(variantNames).toContain('issue_title') + expect(variantNames).toContain('issue_body') + expect(variantNames).toContain('issue_comment') + expect(variantNames).toContain('discussion_title') + expect(variantNames).toContain('discussion_body') + expect(variantNames).toContain('discussion_comment') + expect(variantNames).toContain('pull_request_title') + expect(variantNames).toContain('pull_request_body') + expect(variantNames).toContain('pull_request_comment') + expect(variantNames).toContain('pull_request_review') + expect(variantNames).toContain('pull_request_review_comment') + + // Verify specific variant details + const commitVariant = childParams.find((param) => param.name === 'commit') + expect(commitVariant).toBeDefined() + expect(commitVariant?.description).toContain("commit' secret scanning location type") + expect(commitVariant?.childParamsGroups?.length).toBeGreaterThan(0) + + // Check commit variant has expected properties + const commitProperties = commitVariant?.childParamsGroups?.map((param) => param.name) || [] + expect(commitProperties).toContain('path') + expect(commitProperties).toContain('start_line') + expect(commitProperties).toContain('end_line') + expect(commitProperties).toContain('blob_sha') + expect(commitProperties).toContain('commit_sha') + + const issueTitleVariant = childParams.find((param) => param.name === 'issue_title') + expect(issueTitleVariant).toBeDefined() + expect(issueTitleVariant?.description).toContain("issue_title' secret scanning location type") + expect(issueTitleVariant?.childParamsGroups?.length).toBe(1) + + const issueUrlParam = issueTitleVariant?.childParamsGroups?.[0] + expect(issueUrlParam?.name).toBe('issue_title_url') + expect(issueUrlParam?.description).toContain('API URL to get the associated issue resource') + + // Verify that descriptions are properly rendered + expect(commitVariant?.description).toContain('

') + expect(issueTitleVariant?.description).toContain('

') + }) + + test('should handle mixed oneOf types correctly', async () => { + // Test case where oneOf contains both objects and non-objects + const mockMixedOneOfSchema = { + summary: 'Test webhook with mixed oneOf types', + description: 'A webhook for testing mixed oneOf handling', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + mixed_field: { + oneOf: [ + { + type: 'string', + description: 'String variant', + }, + { + type: 'object', + title: 'object_variant', + description: 'Object variant', + properties: { + field1: { + type: 'string', + description: 'Field 1', + }, + }, + }, + ], + }, + }, + }, + }, + }, + }, + 'x-github': { + 'supported-webhook-types': ['repository'], + subcategory: 'test_mixed_oneof', + }, + } + + const webhook = new Webhook(mockMixedOneOfSchema) + await webhook.process() + + const mixedParam = webhook.bodyParameters.find((param) => param.name === 'mixed_field') + expect(mixedParam).toBeDefined() + + // For mixed types, it should use the fallback behavior (not oneOfObject) + expect(mixedParam?.oneOfObject).toBeFalsy() + expect(mixedParam?.type).toContain('string') + expect(mixedParam?.type).toContain('object') + }) + + test('should handle edge case with empty oneOf array', async () => { + const mockEmptyOneOfSchema = { + summary: 'Test webhook with empty oneOf', + description: 'A webhook for testing empty oneOf handling', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + properties: { + empty_oneof: { + oneOf: [], + }, + }, + }, + }, + }, + }, + 'x-github': { + 'supported-webhook-types': ['repository'], + subcategory: 'test_empty_oneof', + }, + } + + const webhook = new Webhook(mockEmptyOneOfSchema) + + // Should not throw an error + await expect(webhook.process()).resolves.not.toThrow() + + const emptyParam = webhook.bodyParameters.find((param) => param.name === 'empty_oneof') + expect(emptyParam).toBeDefined() + expect(emptyParam?.childParamsGroups?.length || 0).toBe(0) + }) +}) 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