diff --git a/.github/workflows/check-for-spammy-prs.yml b/.github/workflows/check-for-spammy-prs.yml index 241fd9b9f369..94f411e917dd 100644 --- a/.github/workflows/check-for-spammy-prs.yml +++ b/.github/workflows/check-for-spammy-prs.yml @@ -41,8 +41,6 @@ jobs: const changedLines = (file.patch || '') .split('\n') .filter(line => /^[+-]/.test(line)) - ) - return changedLines.length > 0 && changedLines.every(line => line.slice(1).trim() === '') }) diff --git a/.github/workflows/sync-sdk-docs.yml b/.github/workflows/sync-sdk-docs.yml index b8d56344aaca..82a1b2d3a1b4 100644 --- a/.github/workflows/sync-sdk-docs.yml +++ b/.github/workflows/sync-sdk-docs.yml @@ -24,6 +24,7 @@ on: types: [opened, synchronize, reopened] paths: - '.github/workflows/sync-sdk-docs.yml' + - 'content/copilot/get-started/sdk-quickstart.md' - 'src/workflows/sync-sdk-docs/**' concurrency: @@ -77,6 +78,10 @@ jobs: - name: Copy SDK docs run: | mkdir -p "$SDK_DOCS_TARGET" + # Pages relocated out of this tree into hand-authored content are not + # excluded here — they are removed by the RELOCATED_PAGES map in + # src/workflows/sync-sdk-docs/normalize-sdk-docs.ts, which also + # repoints inbound links at their new URLs. rsync -av --exclude='.validation/' --exclude='developer-docs/' "$SDK_TMP/docs/" "$SDK_DOCS_TARGET/" echo "Copied $(find "$SDK_DOCS_TARGET" -name '*.md' | wc -l | tr -d ' ') markdown files" diff --git a/content/admin/backing-up-and-restoring-your-instance/about-the-backup-service-for-github-enterprise-server.md b/content/admin/backing-up-and-restoring-your-instance/about-the-backup-service-for-github-enterprise-server.md index cabc2d65767c..1973d9e36dc7 100644 --- a/content/admin/backing-up-and-restoring-your-instance/about-the-backup-service-for-github-enterprise-server.md +++ b/content/admin/backing-up-and-restoring-your-instance/about-the-backup-service-for-github-enterprise-server.md @@ -9,6 +9,7 @@ category: - Back up and upgrade your instance redirect_from: - /admin/backing-up-and-restoring-your-instance/backup-service-for-github-enterprise-server/about-the-backup-service-for-github-enterprise-server + - /admin/backing-up-and-restoring-your-instance/configuring-backups-on-your-instance --- {% ifversion ghes < 3.20 %} diff --git a/content/code-security/how-tos/manage-security-alerts/manage-secret-scanning-alerts/resolving-alerts.md b/content/code-security/how-tos/manage-security-alerts/manage-secret-scanning-alerts/resolving-alerts.md index 1db51a08b1ea..bd97d1dd7400 100644 --- a/content/code-security/how-tos/manage-security-alerts/manage-secret-scanning-alerts/resolving-alerts.md +++ b/content/code-security/how-tos/manage-security-alerts/manage-secret-scanning-alerts/resolving-alerts.md @@ -48,6 +48,12 @@ Once a secret has been committed to a repository, you should consider the secret > [!NOTE] >{% data variables.product.prodname_secret_scanning_caps %} doesn't automatically close alerts when the corresponding token has been removed from the repository. You must manually close these alerts in the alert list on {% data variables.product.prodname_dotcom %}. +{% ifversion secret-scanning-merge-protection %} + +If a branch ruleset requires {% data variables.product.prodname_secret_scanning %} alerts to be resolved, an open alert introduced by a pull request can block merging. After fixing the exposed secret, close the alert using the following steps. After all blocking alerts are closed, the alerts no longer prevent merging. The rule can continue to block merging until a {% data variables.product.prodname_secret_scanning %} scan completes for the pull request's head commit. + +{% endif %} + {% data reusables.repositories.navigate-to-repo %} {% data reusables.repositories.sidebar-security %} 1. In the left sidebar, under "Vulnerability alerts", click **{% data variables.product.prodname_secret_scanning_caps %}**. diff --git a/content/code-security/how-tos/secure-your-secrets/prevent-future-leaks/block-merges-with-secrets.md b/content/code-security/how-tos/secure-your-secrets/prevent-future-leaks/block-merges-with-secrets.md new file mode 100644 index 000000000000..611c6a52f230 --- /dev/null +++ b/content/code-security/how-tos/secure-your-secrets/prevent-future-leaks/block-merges-with-secrets.md @@ -0,0 +1,82 @@ +--- +title: Blocking pull request merges that contain secrets +shortTitle: Block merges with secrets +intro: Prevent exposed secrets from reaching protected branches by requiring contributors to resolve {% data variables.product.prodname_secret_scanning %} alerts before merging. +permissions: '{% data reusables.permissions.security-org-enable %}{% ifversion enterprise-code-rulesets %}, and enterprise owners{% endif %}' +product: '{% data reusables.gated-features.secret-protection %}' +versions: + feature: secret-scanning-merge-protection +contentType: how-tos +category: + - Protect your secrets +redirect_from: + - /code-security/how-tos/secure-your-secrets/prevent-future-leaks/block-pull-request-merges +--- + +> [!NOTE] +> {% data reusables.secret-scanning.merge-protection-public-preview %} + +The **Require secret scanning alerts are resolved** rule is available for rulesets that target branches in repositories. You can use the rule to block a pull request from merging when either of these conditions applies: + +* A {% data variables.product.prodname_secret_scanning %} scan has not completed for the head commit of the pull request. +* A commit in the pull request introduced an open {% data variables.product.prodname_secret_scanning %} alert that matches a secret type selected in the ruleset. + +The rule supports provider, custom, and generic patterns. It does not support AI-detected secrets. + +## Prerequisites + +The repositories that you want to protect must have: + +* Either {% data variables.product.prodname_GH_secret_protection %} or {% data variables.product.prodname_GHAS %} enabled +* {% data variables.product.prodname_secret_scanning_caps %} enabled. See [AUTOTITLE](/code-security/how-tos/secure-your-secrets/detect-secret-leaks/enable-secret-scanning). + +## Creating a merge protection ruleset for a repository + +{% data reusables.repositories.navigate-to-repo %} +{% data reusables.repositories.sidebar-settings %} +{% data reusables.repositories.repo-rulesets-settings %} +1. Click **New ruleset**. +1. Click **New branch ruleset**. +{% data reusables.repositories.rulesets-general-step %} +{% data reusables.repositories.rulesets-target-branches %} +{% data reusables.repositories.rulesets-require-secret-scanning-alerts-resolved %} +{% data reusables.repositories.rulesets-create-and-insights-step %} + +For information about configuring bypass permissions and other ruleset settings, see [AUTOTITLE](/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/creating-rulesets-for-a-repository). + +## Creating a merge protection ruleset for repositories in an organization{% ifversion enterprise-code-rulesets %} or enterprise{% endif %} + +{% ifversion enterprise-code-rulesets %}You can create this ruleset for repositories in your organization, or create it for an enterprise to apply merge protection consistently across repositories in multiple organizations. + +### Accessing organization ruleset settings{% endif %} + +{% data reusables.profile.access_org %} +{% data reusables.profile.org_settings %} +{% data reusables.organizations.access-ruleset-settings %} + +{% ifversion enterprise-code-rulesets %} + +### Accessing enterprise ruleset settings + +{% data reusables.enterprise-accounts.access-enterprise %} +{% data reusables.enterprise-accounts.policies-tab %} +1. Under "Policies", click **Code**. + +### Configuring the ruleset{% endif %} + +1. Click **New ruleset**. +1. Click **New branch ruleset**. +{% data reusables.repositories.rulesets-general-step %} +{% ifversion enterprise-code-rulesets %} +1. If you are creating an enterprise-level ruleset, under "Target organizations", choose the organizations that the ruleset will apply to. +{% endif %} +1. Under "Target repositories", choose the repositories that the ruleset will apply to. +{% data reusables.repositories.rulesets-target-branches %} +{% data reusables.repositories.rulesets-require-secret-scanning-alerts-resolved %} +{% data reusables.repositories.rulesets-create-and-insights-step %} + +For information about configuring bypass permissions and other ruleset settings, see [AUTOTITLE](/organizations/managing-organization-settings/creating-rulesets-for-repositories-in-your-organization){% ifversion enterprise-code-rulesets %} and [AUTOTITLE](/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-code-governance){% endif %}. + +## Unblocking a pull request + +When this rule blocks a pull request because of open alerts, you must resolve each alert that matches the secret types selected in the ruleset. See [AUTOTITLE](/code-security/how-tos/manage-security-alerts/manage-secret-scanning-alerts/resolving-alerts). diff --git a/content/code-security/how-tos/secure-your-secrets/prevent-future-leaks/index.md b/content/code-security/how-tos/secure-your-secrets/prevent-future-leaks/index.md index e16a907c203f..398a458c9910 100644 --- a/content/code-security/how-tos/secure-your-secrets/prevent-future-leaks/index.md +++ b/content/code-security/how-tos/secure-your-secrets/prevent-future-leaks/index.md @@ -1,7 +1,7 @@ --- title: How-tos for leak prevention shortTitle: Prevent future leaks -intro: Learn how to prevent future secret leaks with {% data variables.product.github %}'s push protection. +intro: Prevent exposed secrets from reaching your repositories and protected branches. versions: fpt: '*' ghes: '*' @@ -10,5 +10,5 @@ contentType: how-tos children: - /enable-push-protection - /manage-user-push-protection + - /block-merges-with-secrets --- - diff --git a/content/copilot/get-started/enterprise-ai-governance.md b/content/copilot/get-started/enterprise-ai-governance.md index 151c8c0a22e3..831c60673078 100644 --- a/content/copilot/get-started/enterprise-ai-governance.md +++ b/content/copilot/get-started/enterprise-ai-governance.md @@ -22,7 +22,7 @@ journeyTracks: description: 'Use {% data variables.product.github %}''s governance features to stay in control of your codebase and compliance requirements.' guides: - href: '/copilot/tutorials/roll-out-at-scale/govern-at-scale/govern-for-adoption' - - href: '/copilot/concepts/policies' + - href: '/copilot/concepts/enterprise/policies' - href: '/copilot/tutorials/roll-out-at-scale/govern-at-scale/maintain-codebase-standards' - href: '/copilot/how-tos/administer-copilot/manage-for-enterprise/review-audit-logs' - id: 'adopting_agents' @@ -30,7 +30,7 @@ journeyTracks: description: 'Learn what agents can do for your enterprise, and prepare to roll them out.' guides: - href: '/copilot/tutorials/roll-out-at-scale/enable-developers/integrate-ai-agents' - - href: '/copilot/concepts/agents/enterprise-management' + - href: '/copilot/concepts/enterprise/agent-management' - href: '/copilot/tutorials/cloud-agent/build-guardrails' - href: '/copilot/how-tos/administer-copilot/manage-mcp-usage/configure-enterprise-allowlist' - id: 'enable_agents' @@ -47,6 +47,6 @@ journeyTracks: title: 'Adopting new features' description: 'Expand your capabilities by assessing and rolling out any new feature or model.' guides: - - href: '/copilot/concepts/learning-about-new-features-and-models' + - href: '/copilot/concepts/enterprise/learning-about-new-features-and-models' - href: '/copilot/tutorials/roll-out-at-scale/govern-at-scale/pilot-a-feature-or-model' --- diff --git a/content/copilot/get-started/index.md b/content/copilot/get-started/index.md index 04fd99c3a261..62e71e31c8f0 100644 --- a/content/copilot/get-started/index.md +++ b/content/copilot/get-started/index.md @@ -8,6 +8,7 @@ children: - /quickstart - /cli-quickstart - /quickstart-copilot-app + - /sdk-quickstart - /what-is-github-copilot - /plans - /features diff --git a/content/copilot/how-tos/copilot-sdk/getting-started.md b/content/copilot/get-started/sdk-quickstart.md similarity index 99% rename from content/copilot/how-tos/copilot-sdk/getting-started.md rename to content/copilot/get-started/sdk-quickstart.md index 0b14f781ee31..33db9d2e1cab 100644 --- a/content/copilot/how-tos/copilot-sdk/getting-started.md +++ b/content/copilot/get-started/sdk-quickstart.md @@ -1,21 +1,22 @@ --- title: Build your first Copilot-powered app -shortTitle: Getting Started +shortTitle: Copilot SDK quickstart +allowTitleToDifferFromFilename: true intro: >- In this tutorial, you'll use the Copilot SDK to build a command-line assistant. You'll start with the basics, add streaming responses, then add custom tools - giving Copilot the ability to call your code. versions: - fpt: '*' - ghec: '*' + feature: copilot redirect_from: - /copilot/how-tos/copilot-sdk/sdk-getting-started -contentType: how-tos + - /copilot/how-tos/copilot-sdk/getting-started +contentType: get-started +category: + - Quickstarts + - Integrate Copilot with your tools --- - - - **What you'll build:** ```text diff --git a/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md b/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md index 295be57c903a..ed336b745a2f 100644 --- a/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md @@ -20,6 +20,9 @@ docsTeamMetrics: You can use the `/sandbox` slash command to grant extra paths, adjust network access, or turn sandboxing on or off. +> [!NOTE] +> If you get your {% data variables.product.prodname_copilot_short %} license from an enterprise, some or all sandbox settings may be controlled by enterprise managed settings. A managed setting is labeled `(managed)` in the `/sandbox` interface and can't be changed. + For a conceptual overview of cloud and local sandboxes for {% data variables.product.prodname_copilot_short %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). ## Opening the sandbox configuration diff --git a/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md b/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md index 53a63a6089f0..9514ea525fb9 100644 --- a/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md @@ -48,3 +48,5 @@ Enterprise owners can control cloud sandbox access for all organizations in the * [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes) * [AUTOTITLE](/billing/concepts/product-billing/cloud-and-local-sandboxes) +* [AUTOTITLE](/copilot/reference/enterprise-administrators/enterprise-managed-settings#sandbox) + diff --git a/content/copilot/how-tos/copilot-sdk/auth/authenticate.md b/content/copilot/how-tos/copilot-sdk/auth/authenticate.md index 7b6068443725..efd6654f5bb8 100644 --- a/content/copilot/how-tos/copilot-sdk/auth/authenticate.md +++ b/content/copilot/how-tos/copilot-sdk/auth/authenticate.md @@ -404,5 +404,5 @@ const client = new CopilotClient({ ## Next steps * [AUTOTITLE](/copilot/how-tos/copilot-sdk/auth/byok) - Learn how to use your own API keys -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) - Build your first Copilot-powered app +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) - Build your first Copilot-powered app * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/mcp) - Connect to external tools diff --git a/content/copilot/how-tos/copilot-sdk/auth/byok.md b/content/copilot/how-tos/copilot-sdk/auth/byok.md index a5ec405399ee..6624808ec975 100644 --- a/content/copilot/how-tos/copilot-sdk/auth/byok.md +++ b/content/copilot/how-tos/copilot-sdk/auth/byok.md @@ -594,4 +594,4 @@ foundry model run phi-4-mini ## Next steps * [AUTOTITLE](/copilot/how-tos/copilot-sdk/auth) - Learn about all authentication methods -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) - Build your first Copilot-powered app +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) - Build your first Copilot-powered app diff --git a/content/copilot/how-tos/copilot-sdk/features/hooks.md b/content/copilot/how-tos/copilot-sdk/features/hooks.md index 3958e751636a..172c78fd7633 100644 --- a/content/copilot/how-tos/copilot-sdk/features/hooks.md +++ b/content/copilot/how-tos/copilot-sdk/features/hooks.md @@ -890,7 +890,7 @@ For full type definitions, input/output field tables, and additional examples fo ## See also -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/custom-agents) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/streaming-events) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/troubleshooting/debugging) diff --git a/content/copilot/how-tos/copilot-sdk/features/mcp.md b/content/copilot/how-tos/copilot-sdk/features/mcp.md index d23b054c0bb9..9569df0f34d1 100644 --- a/content/copilot/how-tos/copilot-sdk/features/mcp.md +++ b/content/copilot/how-tos/copilot-sdk/features/mcp.md @@ -340,7 +340,7 @@ For detailed debugging guidance, see the **[AUTOTITLE](/copilot/how-tos/copilot- * [Model Context Protocol Specification](https://modelcontextprotocol.io/) * [MCP Servers Directory](https://github.com/modelcontextprotocol/servers) - Community MCP servers * [GitHub MCP Server](https://github.com/github/github-mcp-server) - Official GitHub MCP server -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) - SDK basics and custom tools +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) - SDK basics and custom tools * [AUTOTITLE](/copilot/how-tos/copilot-sdk/troubleshooting/debugging) - SDK-wide debugging ## See also diff --git a/content/copilot/how-tos/copilot-sdk/features/skills.md b/content/copilot/how-tos/copilot-sdk/features/skills.md index 17676dc35f94..71fa9121dc63 100644 --- a/content/copilot/how-tos/copilot-sdk/features/skills.md +++ b/content/copilot/how-tos/copilot-sdk/features/skills.md @@ -373,6 +373,6 @@ If multiple skills provide conflicting instructions: ## See also -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started#create-custom-agents) - Define specialized AI personas -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started#step-4-add-a-custom-tool) - Build your own tools +* [AUTOTITLE](/copilot/get-started/sdk-quickstart#create-custom-agents) - Define specialized AI personas +* [AUTOTITLE](/copilot/get-started/sdk-quickstart#step-4-add-a-custom-tool) - Build your own tools * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/mcp) - Connect external tool providers diff --git a/content/copilot/how-tos/copilot-sdk/features/steering-and-queueing.md b/content/copilot/how-tos/copilot-sdk/features/steering-and-queueing.md index b1576cef0332..3669f9c5c2ca 100644 --- a/content/copilot/how-tos/copilot-sdk/features/steering-and-queueing.md +++ b/content/copilot/how-tos/copilot-sdk/features/steering-and-queueing.md @@ -546,7 +546,7 @@ class InteractiveChat { ## See also -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started): Set up a session and send messages +* [AUTOTITLE](/copilot/get-started/sdk-quickstart): Set up a session and send messages * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/custom-agents): Define specialized agents with scoped tools * [AUTOTITLE](/copilot/how-tos/copilot-sdk/hooks/hooks-overview): React to session lifecycle events * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/session-persistence): Resume sessions across restarts diff --git a/content/copilot/how-tos/copilot-sdk/hooks/hooks-overview.md b/content/copilot/how-tos/copilot-sdk/hooks/hooks-overview.md index 2a5df49b0ab7..58541e6eeb89 100644 --- a/content/copilot/how-tos/copilot-sdk/hooks/hooks-overview.md +++ b/content/copilot/how-tos/copilot-sdk/hooks/hooks-overview.md @@ -277,6 +277,6 @@ const session = await client.createSession({ ## See also -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started#step-4-add-a-custom-tool) +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) +* [AUTOTITLE](/copilot/get-started/sdk-quickstart#step-4-add-a-custom-tool) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/troubleshooting/debugging) diff --git a/content/copilot/how-tos/copilot-sdk/index.md b/content/copilot/how-tos/copilot-sdk/index.md index 094b1f3411a1..2285a39ff9fa 100644 --- a/content/copilot/how-tos/copilot-sdk/index.md +++ b/content/copilot/how-tos/copilot-sdk/index.md @@ -9,7 +9,6 @@ versions: ghec: '*' contentType: how-tos children: - - /getting-started - /auth - /features - /hooks diff --git a/content/copilot/how-tos/copilot-sdk/integrations/microsoft-agent-framework.md b/content/copilot/how-tos/copilot-sdk/integrations/microsoft-agent-framework.md index 2bc40d5b2b24..ce4a8769c230 100644 --- a/content/copilot/how-tos/copilot-sdk/integrations/microsoft-agent-framework.md +++ b/content/copilot/how-tos/copilot-sdk/integrations/microsoft-agent-framework.md @@ -33,7 +33,7 @@ The Microsoft Agent Framework is the unified successor to Semantic Kernel and Au Before you begin, ensure you have: -* A working [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) in your language of choice +* A working [AUTOTITLE](/copilot/get-started/sdk-quickstart) in your language of choice * A GitHub Copilot subscription (Individual, Business, or Enterprise) * The Copilot CLI installed or available via the SDK's bundled CLI @@ -593,7 +593,7 @@ client.stop().get(); ### Copilot SDK options (passed through) -All standard [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) options are still available when creating the underlying Copilot client. The MAF wrapper delegates to the SDK under the hood: +All standard [AUTOTITLE](/copilot/get-started/sdk-quickstart) options are still available when creating the underlying Copilot client. The MAF wrapper delegates to the SDK under the hood: | SDK Feature | MAF Support | |-------------|-------------| @@ -661,7 +661,7 @@ catch (AgentException ex) ## See also -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started): initial Copilot SDK setup +* [AUTOTITLE](/copilot/get-started/sdk-quickstart): initial Copilot SDK setup * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/custom-agents): define specialized sub-agents within the SDK * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/skills): reusable prompt modules * [Microsoft Agent Framework documentation](https://learn.microsoft.com/en-us/agent-framework/agents/providers/github-copilot): official MAF docs for the Copilot provider diff --git a/content/copilot/how-tos/copilot-sdk/setup/bundled-cli.md b/content/copilot/how-tos/copilot-sdk/setup/bundled-cli.md index 7f9f3b012772..51076cb21120 100644 --- a/content/copilot/how-tos/copilot-sdk/setup/bundled-cli.md +++ b/content/copilot/how-tos/copilot-sdk/setup/bundled-cli.md @@ -215,4 +215,4 @@ Session state persists at `~/.copilot/session-state/{sessionId}/`. * **[AUTOTITLE](/copilot/how-tos/copilot-sdk/auth/byok)**: Use your own model provider keys * **[AUTOTITLE](/copilot/how-tos/copilot-sdk/features/session-persistence)**: Advanced session management -* **[AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started)**: Build a complete app +* **[AUTOTITLE](/copilot/get-started/sdk-quickstart)**: Build a complete app diff --git a/content/copilot/how-tos/copilot-sdk/setup/choosing-a-setup-path.md b/content/copilot/how-tos/copilot-sdk/setup/choosing-a-setup-path.md index 79d5e41f9608..34c16e7d36cd 100644 --- a/content/copilot/how-tos/copilot-sdk/setup/choosing-a-setup-path.md +++ b/content/copilot/how-tos/copilot-sdk/setup/choosing-a-setup-path.md @@ -101,7 +101,7 @@ All guides assume you have: * Go: `go get github.com/github/copilot-sdk/go` (requires separate CLI installation) * .NET: `dotnet add package GitHub.Copilot.SDK` -If you're brand new, start with the **[AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started)** first, then come back here for production configuration. +If you're brand new, start with the **[AUTOTITLE](/copilot/get-started/sdk-quickstart)** first, then come back here for production configuration. ## Next steps diff --git a/content/copilot/how-tos/copilot-sdk/setup/local-cli.md b/content/copilot/how-tos/copilot-sdk/setup/local-cli.md index 541c481c4038..8efe570391ed 100644 --- a/content/copilot/how-tos/copilot-sdk/setup/local-cli.md +++ b/content/copilot/how-tos/copilot-sdk/setup/local-cli.md @@ -177,5 +177,5 @@ Session state is stored locally at `~/.copilot/session-state/{sessionId}/`. ## Next steps * **[AUTOTITLE](/copilot/how-tos/copilot-sdk/setup/bundled-cli)**: Use the SDK's built-in CLI (recommended for most use cases) -* **[AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started)**: Build a complete interactive app +* **[AUTOTITLE](/copilot/get-started/sdk-quickstart)**: Build a complete interactive app * **[AUTOTITLE](/copilot/how-tos/copilot-sdk/auth/authenticate)**: All auth methods in detail diff --git a/content/copilot/how-tos/copilot-sdk/troubleshooting/compatibility.md b/content/copilot/how-tos/copilot-sdk/troubleshooting/compatibility.md index 4499e127ded7..5a1f9a6cd656 100644 --- a/content/copilot/how-tos/copilot-sdk/troubleshooting/compatibility.md +++ b/content/copilot/how-tos/copilot-sdk/troubleshooting/compatibility.md @@ -308,7 +308,7 @@ console.log("Protocol version:", status.protocolVersion); ## See also -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/hooks/hooks-overview) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/mcp) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/troubleshooting/debugging) diff --git a/content/copilot/how-tos/copilot-sdk/troubleshooting/debugging.md b/content/copilot/how-tos/copilot-sdk/troubleshooting/debugging.md index bcd88f945ae6..5f99af3540d1 100644 --- a/content/copilot/how-tos/copilot-sdk/troubleshooting/debugging.md +++ b/content/copilot/how-tos/copilot-sdk/troubleshooting/debugging.md @@ -538,7 +538,7 @@ If you're still stuck: ## See also -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) * [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/mcp) - MCP configuration and setup * [AUTOTITLE](/copilot/how-tos/copilot-sdk/troubleshooting/mcp-debugging) - Detailed MCP troubleshooting * [API Reference](https://github.com/github/copilot-sdk) diff --git a/content/copilot/how-tos/set-up/set-up-for-self.md b/content/copilot/how-tos/set-up/set-up-for-self.md index 0ce282089442..2357c43ade78 100644 --- a/content/copilot/how-tos/set-up/set-up-for-self.md +++ b/content/copilot/how-tos/set-up/set-up-for-self.md @@ -23,7 +23,7 @@ There are a few ways that you can get access to {% data variables.product.prodna * **Sign up for a paid plan**. You can subscribe to one of these plans: * **{% data variables.copilot.copilot_pro_short %}**, which includes access to premium models and a monthly allowance of {% data variables.product.prodname_ai_credits_short %}. [Subscribe to {% data variables.copilot.copilot_pro_short %}](https://github.com/github-copilot/signup?ref_product=copilot&ref_type=purchase&ref_style=text&ref_plan=pro). - * **{% data variables.copilot.copilot_pro_plus_short %}**, which includes a higher monthly allowance of {% data variables.product.prodname_ai_credits_short %} and access to all available models. [Subscribe to {% data variables.copilot.copilot_pro_plus_short %}](https://github.com/github-copilot/signup?ref_product=copilot&ref_type=purchase&ref_style=text&ref_plan=pro). + * **{% data variables.copilot.copilot_pro_plus_short %}**, which includes a higher monthly allowance of {% data variables.product.prodname_ai_credits_short %} and access to all available models. [Subscribe to {% data variables.copilot.copilot_pro_plus_short %}](https://github.com/github-copilot/signup?ref_product=copilot&ref_type=purchase&ref_style=text&ref_plan=pro-plus). * **{% data variables.copilot.copilot_max_short %}**, which includes advanced AI models and our highest individual monthly allowance of {% data variables.product.prodname_ai_credits_short %}. [Subscribe to {% data variables.copilot.copilot_max_short %}](https://github.com/settings/billing/licensing?ref_product=copilot&ref_type=purchase&ref_style=text&ref_plan=max). * **Use {% data variables.product.prodname_copilot_short %} through your organization or enterprise**. If you're part of an organization or enterprise with a {% data variables.product.prodname_copilot_short %} plan, you can request access at [https://github.com/settings/copilot](https://github.com/settings/copilot) under "Get {% data variables.product.prodname_copilot_short %} from an organization." diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/use-cloud-agent-on-github.md b/content/copilot/how-tos/use-copilot-agents/cloud-agent/use-cloud-agent-on-github.md index dd6f4579c433..1be6dcd31f13 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/use-cloud-agent-on-github.md +++ b/content/copilot/how-tos/use-copilot-agents/cloud-agent/use-cloud-agent-on-github.md @@ -138,11 +138,30 @@ When an {% data variables.product.prodname_actions %} workflow run fails on a pu ## Continuing work on a pull request +You can ask {% data variables.product.prodname_copilot_short %} to make changes or address review comments on an existing pull request. You can then track the resulting session and provide follow-up instructions. + +### Asking {% data variables.product.prodname_copilot_short %} to make changes + You can mention `@copilot` in a comment on any pull request to ask {% data variables.product.prodname_copilot_short %} to make changes. This works on pull requests created by {% data variables.product.prodname_copilot_short %} and on pull requests you or others created. By default, {% data variables.product.prodname_copilot_short %} pushes commits directly to the pull request branch. To create a separate pull request instead, describe that in your comment. You can also check out the branch and push changes yourself. -Batch review comments instead of submitting them individually. When submitting a pull request comment (not a review or review comment) through the {% data variables.product.github %} web interface, select a model with the model picker. {% data variables.product.prodname_copilot_short %} uses the model from the original pull request by default. +When submitting a pull request comment (not a review or review comment) through the {% data variables.product.github %} web interface, select a model with the model picker. {% data variables.product.prodname_copilot_short %} uses the model from the original pull request by default. + +### Delegating review comments + +You can delegate review comments to have {% data variables.product.prodname_copilot_short %} implement feedback from human reviewers and {% data variables.copilot.copilot_code-review %}. + +1. In the pull request, open the **Files changed** tab. +1. Navigate to the first review comment you want {% data variables.product.prodname_copilot_short %} to implement. + * To delegate one comment, click **Fix with {% data variables.product.prodname_copilot_short %}**. + * To delegate multiple comments, click **Add to batch**. Continue to add the comments you want {% data variables.product.prodname_copilot_short %} to work on. +1. In the **Manage batch** panel, add any additional instructions, and optionally select a model with the model picker. +1. Choose how you want {% data variables.product.prodname_copilot_short %} to apply the changes: + * To commit the changes directly to the branch, click **{% octicon "agent" aria-label="The Agents icon" %} Fix and commit**. + * To have {% data variables.product.prodname_copilot_short %} create a new pull request with the changes, click **Fix and open pull request** from the dropdown menu. + +### Tracking and continuing a session {% data reusables.copilot.cloud-agent.write-access-required %} diff --git a/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md b/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md index 8c52aa19c444..c667854ae6d8 100644 --- a/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md +++ b/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md @@ -21,9 +21,9 @@ For instructions on creating the file, see [AUTOTITLE](/copilot/how-tos/administ | Key | Purpose | {% data variables.copilot.copilot_cli_short %} | {% data variables.product.prodname_vscode_shortname %} | {% data variables.copilot.github_copilot_app %} | {% data variables.copilot.copilot_cloud_agent %} | {% data variables.product.prodname_jetbrains_ides %} | | --- | --- | --- | --- | --- | --- | --- | | `permissions.disableBypassPermissionsMode` | Disables bypass or YOLO-style allow-all behavior | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | -| `permissions.deny` | Blocks specific operations | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | -| `permissions.ask` | Requires a fresh human approval before specific operations can proceed | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | -| `permissions.allow` | Permits specific operations to proceed without a prompt | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | +| `permissions.deny` | Blocks specific operations | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | +| `permissions.ask` | Requires a fresh human approval before specific operations can proceed | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | +| `permissions.allow` | Permits specific operations to proceed without a prompt | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | | `model` | Sets your preferred model as the default for new conversations | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | | `enabledPlugins` | Enables or disables specific plugins by key | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | | `extraKnownMarketplaces` | Adds plugin marketplaces that users can access | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | @@ -172,6 +172,8 @@ This key is overridable by enterprise team mapping. In your `{% data variables.c ### deny, ask, allow +In {% data variables.product.prodname_vscode_shortname %}, these granular permission rules apply to {% data variables.product.prodname_copilot_short %} sessions that use Agent Host. The `permissions.disableBypassPermissionsMode` setting has broader {% data variables.product.prodname_vscode_shortname %} support and isn't limited to Agent Host. + The `permissions.deny`, `permissions.ask`, and `permissions.allow` keys use **deny > ask > allow** precedence. If an MDM-managed, server-managed, or file-based source defines any permission rule—or if any applicable source declares an `allow` list—an unmatched supported operation defaults to requiring approval. Otherwise, it follows the ordinary permission flow. * `deny` blocks specific operations, regardless of whether they also match an `ask` or `allow` rule. A deny rule set by any managed settings source blocks the operation for all users regardless of rules in the other sources. diff --git a/content/copilot/responsible-use/agents.md b/content/copilot/responsible-use/agents.md index 6ccf2ca743bb..9c744465e944 100644 --- a/content/copilot/responsible-use/agents.md +++ b/content/copilot/responsible-use/agents.md @@ -285,7 +285,7 @@ For additional guidance on the responsible use of Copilot agentic features, we r * [AUTOTITLE](/copilot/tutorials/cloud-agent/get-the-best-results) * [AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-environment) * [AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/customize-the-firewall) -* [AUTOTITLE](/copilot/how-tos/copilot-sdk/getting-started) +* [AUTOTITLE](/copilot/get-started/sdk-quickstart) * [AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/configure-mcp-servers) * [AUTOTITLE](/copilot/concepts/agents/copilot-cli/about-copilot-cli) * [AUTOTITLE](/copilot/concepts/agents/github-copilot-app) diff --git a/content/pull-requests/how-tos/review-pull-requests/incorporating-feedback-in-your-pull-request.md b/content/pull-requests/how-tos/review-pull-requests/incorporating-feedback-in-your-pull-request.md index 2ec8f7488301..e42cdc06da06 100644 --- a/content/pull-requests/how-tos/review-pull-requests/incorporating-feedback-in-your-pull-request.md +++ b/content/pull-requests/how-tos/review-pull-requests/incorporating-feedback-in-your-pull-request.md @@ -40,6 +40,12 @@ Each person who suggested a change included in the commit will be a co-author of 1. In the commit message field, type a short, meaningful commit message that describes the change you made to the file or files. 1. Click **Commit changes**. +{% ifversion fpt or ghec %} +## Delegating review comments to {% data variables.product.prodname_copilot_short %} + +If you have access to {% data variables.copilot.copilot_cloud_agent %}, you can delegate review comments to have {% data variables.product.prodname_copilot_short %} implement the feedback. For more information, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/use-cloud-agent-on-github#delegating-review-comments). +{% endif %} + ## Re-requesting a review For example, you can re-request a review after you've made substantial changes to your pull request. diff --git a/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md b/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md index 8866e5313c2d..7d357280a53f 100644 --- a/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md +++ b/content/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets.md @@ -211,6 +211,24 @@ Enabling force pushes will not override any other rules. For example, if a branc If a site administrator has blocked force pushes to the default branch only, you can still enable force pushes for any other branch or tag.{% endif %} +{% ifversion secret-scanning-merge-protection %} + +## Require {% data variables.product.prodname_secret_scanning %} alerts are resolved + +> [!NOTE] +> {% data reusables.secret-scanning.merge-protection-public-preview %} + +If your repositories use {% data variables.product.prodname_secret_scanning %}, you can prevent a pull request from merging when either of these conditions applies: + +* A {% data variables.product.prodname_secret_scanning %} scan has not completed for the head commit of the pull request. +* A commit in the pull request introduced an open {% data variables.product.prodname_secret_scanning %} alert that matches a secret type selected in the ruleset. + +You can configure the rule for provider, custom, and generic patterns. AI-detected secrets are not supported. + +For more information, see [AUTOTITLE](/code-security/how-tos/secure-your-secrets/prevent-future-leaks/block-merges-with-secrets). + +{% endif %} + ## Require {% data variables.product.prodname_code_scanning %} results If your repositories are configured with {% data variables.product.prodname_code_scanning %}, you can use rulesets to prevent pull requests from being merged when one of the following conditions is met: diff --git a/data/features/secret-scanning-merge-protection.yml b/data/features/secret-scanning-merge-protection.yml new file mode 100644 index 000000000000..b49bf679fff2 --- /dev/null +++ b/data/features/secret-scanning-merge-protection.yml @@ -0,0 +1,7 @@ +# Reference: https://github.com/github/docs-content/issues/24116 +# Public preview for requiring secret scanning alerts to be resolved before merging + +versions: + fpt: '*' + ghec: '*' + ghes: '>=3.24' diff --git a/data/reusables/repositories/rulesets-require-secret-scanning-alerts-resolved.md b/data/reusables/repositories/rulesets-require-secret-scanning-alerts-resolved.md new file mode 100644 index 000000000000..60f01b621d48 --- /dev/null +++ b/data/reusables/repositories/rulesets-require-secret-scanning-alerts-resolved.md @@ -0,0 +1,5 @@ +1. Under "Branch protections", select **Require {% data variables.product.prodname_secret_scanning %} alerts are resolved**. +1. Under "Secret types", select one or more types of secrets that should block merging: + * **Provider patterns** + * **Custom patterns** + * **Generic patterns** diff --git a/data/reusables/secret-scanning/merge-protection-public-preview.md b/data/reusables/secret-scanning/merge-protection-public-preview.md new file mode 100644 index 000000000000..2affc184ebb0 --- /dev/null +++ b/data/reusables/secret-scanning/merge-protection-public-preview.md @@ -0,0 +1 @@ +The rule to require {% data variables.product.prodname_secret_scanning %} alerts to be resolved before merging is in {% data variables.release-phases.public_preview %} and subject to change. diff --git a/src/redirects/lib/static/redirect-exceptions.txt b/src/redirects/lib/static/redirect-exceptions.txt index 02a9da69714b..9f7a56931291 100644 --- a/src/redirects/lib/static/redirect-exceptions.txt +++ b/src/redirects/lib/static/redirect-exceptions.txt @@ -48,8 +48,3 @@ - /github-ae@latest/admin/overview/about-data-residency - /github-ae@latest/admin/overview/deploying-github-ae - /github-ae@latest/admin/overview/initializing-github-ae - -# The legacy backup-utils docs are deprecated from 3.22, but they still need to exist in previous supported versions -# So we need to set up a redirect for every new GHES versions until 3.22 is the oldest supported versions -/enterprise-server@3.22/admin/backing-up-and-restoring-your-instance/about-the-backup-service-for-github-enterprise-server -- /enterprise-server@3.22/admin/backing-up-and-restoring-your-instance/configuring-backups-on-your-instance diff --git a/src/workflows/sync-sdk-docs/normalize-sdk-docs.ts b/src/workflows/sync-sdk-docs/normalize-sdk-docs.ts index 37bf35d3af3c..a4a1ec29566f 100644 --- a/src/workflows/sync-sdk-docs/normalize-sdk-docs.ts +++ b/src/workflows/sync-sdk-docs/normalize-sdk-docs.ts @@ -4,6 +4,8 @@ * Normalizes Copilot SDK docs for publishing on docs.github.com. * * For every .md file in the SDK docs directory, this script: + * - Removes pages that have been relocated out of the synced tree + * (see RELOCATED_PAGES) and repoints inbound links at their new URLs * - Renames README.md files to index.md (the SDK repo uses README.md as the * landing page for each docs directory; docs-internal requires index.md) * - Adds YAML frontmatter (title, intro, shortTitle, versions, contentType) @@ -41,6 +43,35 @@ const { values: args } = parseArgs({ const CONTENT_DIR = path.resolve(args['content-dir'] as string) const SDK_DOCS_DIR = path.resolve(args['sdk-docs-dir'] as string) +/** + * Pages that have been relocated OUT of the synced SDK docs tree into + * hand-authored content elsewhere in docs-internal. + * + * Keys are paths relative to the SDK docs root, exactly as they appear upstream + * in github/copilot-sdk's `docs/` directory. Values are the docs.github.com URL + * the page now lives at. + * + * Each entry does two inseparable things on every sync: + * 1. Deletes the upstream copy after it is rsynced in (Step 0a), so the page + * is not republished at its old URL — that URL is now a `redirect_from` on + * the hand-authored page and must stay vacant. + * 2. Teaches the internal-link rewriter (Step 3) to point inbound relative + * links at the new URL, instead of logging "target missing" and leaving a + * raw `../getting-started.md` link in published content. + * + * Both halves must stay together, which is why this lives here rather than as an + * rsync `--exclude` in .github/workflows/sync-sdk-docs.yml: excluding the file + * at copy time without remapping its links would ship ~17 broken links. + * + * Destinations are validated on every run; see validateRelocatedDestinations(). + */ +const RELOCATED_PAGES: Record = { + 'getting-started.md': '/copilot/get-started/sdk-quickstart', +} + +/** Relocated pages whose upstream source file was not found during this sync. */ +const missingRelocatedSources: string[] = [] + if (!fs.existsSync(CONTENT_DIR)) { console.error(`Content directory not found: ${CONTENT_DIR}`) process.exit(1) @@ -142,6 +173,98 @@ function convertReadmesToIndex(): void { } } +/** + * Return the new URL for a relocated page, given an absolute path inside the + * SDK docs tree. Returns undefined for pages that have not been relocated. + */ +function relocatedUrlFor(absPath: string): string | undefined { + return RELOCATED_PAGES[path.relative(SDK_DOCS_DIR, absPath)] +} + +/** + * Step 0a: Delete pages that have been relocated out of the synced tree. + * + * The sync `rm -rf`s and re-rsyncs this whole directory every run, so a page + * moved into hand-authored content elsewhere in docs-internal would otherwise + * reappear at its old URL on the next sync and collide with the `redirect_from` + * that now claims it. (Redirect compilation resolves that collision by dropping + * the redirect, so the deletion is a hard invariant, not a tidiness measure.) + * + * This runs before every other step, so keys stay expressed in upstream terms: + * before Step 0 renames `README.md` to `index.md`, and before Step 1 so that + * `getChildren()` never sees the file and the parent index.md's `children` + * array is free of dangling entries. + * + * A missing source is reported rather than ignored: it usually means upstream + * renamed the file, in which case the page silently republishes under a new URL + * and the vacated URL may be reclaimed. It does not fail the sync, because + * github/copilot-sdk is a separate repo that may legitimately delete the page + * once docs-internal is canonical. + */ +function removeRelocatedPages(): void { + for (const [relPath, newUrl] of Object.entries(RELOCATED_PAGES)) { + const absPath = path.join(SDK_DOCS_DIR, relPath) + if (!fs.existsSync(absPath)) { + missingRelocatedSources.push(relPath) + console.log(` WARN (relocated source missing upstream): ${relPath}`) + continue + } + fs.rmSync(absPath) + console.log(` RELOCATED: ${relPath} -> ${newUrl}`) + } +} + +/** + * Validate that every relocated page's destination actually exists in the + * hand-authored content tree. A typo or an unrelated rename would otherwise + * silently repoint every inbound link at a 404. + * + * Unlike a missing upstream source, this is entirely within docs-internal's + * control, so it fails the sync. It runs before anything mutates the tree. + */ +function validateRelocatedDestinations(): void { + const broken: string[] = [] + + for (const [relPath, newUrl] of Object.entries(RELOCATED_PAGES)) { + const base = path.join(CONTENT_DIR, newUrl) + if (!fs.existsSync(`${base}.md`) && !fs.existsSync(path.join(base, 'index.md'))) { + broken.push(`${relPath} -> ${newUrl}`) + } + } + + if (broken.length === 0) return + + console.error('RELOCATED_PAGES points at destinations that do not exist in the content tree:') + for (const entry of broken) console.error(` ${entry}`) + console.error('Update RELOCATED_PAGES in src/workflows/sync-sdk-docs/normalize-sdk-docs.ts.') + process.exit(1) +} + +/** + * Report relocated pages whose upstream source vanished, to the Actions job + * summary linked from the generated PR. Mirrors reportUnbalancedMarkers(): the + * run log alone is not something a PR reviewer will see. + */ +function reportMissingRelocatedSources(): void { + const summaryPath = process.env.GITHUB_STEP_SUMMARY + if (missingRelocatedSources.length === 0 || !summaryPath) return + + const lines = [ + '### ⚠️ Relocated page missing from upstream', + '', + 'These pages are listed in `RELOCATED_PAGES` but no longer exist in', + '[copilot-sdk docs](https://github.com/github/copilot-sdk/tree/main/docs).', + 'If upstream **renamed** the file, it is now republishing under a new URL and may have', + 'reclaimed the URL this move vacated — update `RELOCATED_PAGES`. If upstream', + '**deleted** it deliberately, remove the entry instead.', + '', + ...missingRelocatedSources.map((source) => `* \`${source}\``), + '', + ] + + fs.appendFileSync(summaryPath, lines.join('\n')) +} + /** Convert a filename slug to a title-case short title. */ function slugToTitle(slug: string): string { const ACRONYMS: Record = { @@ -303,6 +426,16 @@ function rewriteInternalLinks(filePath: string): void { const resolved = path.resolve(dir, rawPath) if (!resolved.startsWith(CONTENT_DIR)) return _match + + // Pages relocated out of the synced tree no longer exist on disk, so the + // existence check below would leave a raw relative link. Repoint them at + // their new home instead. + const relocatedUrl = relocatedUrlFor(resolved) + if (relocatedUrl) { + changed = true + return `[AUTOTITLE](${relocatedUrl}${anchor ? `#${anchor}` : ''})` + } + if (!fs.existsSync(resolved)) { console.log(` WARN (target missing): ${href} in ${path.relative(SDK_DOCS_DIR, filePath)}`) return _match @@ -896,9 +1029,17 @@ function suppressSdkLintRules(filePath: string): void { console.log(`Normalizing SDK docs in: ${SDK_DOCS_DIR}`) console.log(`Content directory: ${CONTENT_DIR}\n`) +// Step 0a: Remove pages relocated out of the synced tree (see RELOCATED_PAGES). +// Runs first so keys stay expressed in upstream terms (before README->index +// renaming) and so getChildren() never lists a relocated page. +validateRelocatedDestinations() +console.log('--- Removing relocated pages ---\n') +removeRelocatedPages() +reportMissingRelocatedSources() + // Step 0: Rename README.md files to index.md (copilot-sdk uses README.md as // directory landing pages; docs-internal requires index.md). -console.log('--- Renaming README.md files to index.md ---\n') +console.log('\n--- Renaming README.md files to index.md ---\n') convertReadmesToIndex() // Step 1: Add frontmatter diff --git a/src/workflows/unallowed-contribution-filters.yml b/src/workflows/unallowed-contribution-filters.yml index e6bd35f29e01..9930c22b66c3 100644 --- a/src/workflows/unallowed-contribution-filters.yml +++ b/src/workflows/unallowed-contribution-filters.yml @@ -4,7 +4,6 @@ notAllowed: - '.github/**' - 'data/reusables/rai/**' - '.vscode/**' - - 'assets/**' - 'config/**' - 'contributing/**' - 'src/**'