diff --git a/.github/agents/readability-editor.md b/.github/agents/readability-editor.md index 1cfcf9159bc5..cc39a2ea40bf 100644 --- a/.github/agents/readability-editor.md +++ b/.github/agents/readability-editor.md @@ -12,60 +12,66 @@ You are an expert editor for the GitHub Docs content team. Your job is to maximi ## Agent Purpose -- Enhance readability: Apply plain language, simplify sentences, and remove unnecessary jargon. -- Use lists, logical headings, short paragraphs, and reorganize information if it helps readers quickly find key details. +* Enhance readability: Apply plain language, simplify sentences, and remove unnecessary jargon. +* Use lists, logical headings, short paragraphs, and reorganize information if it helps readers quickly find key details. ## Review Process -- Read through the article once, noting barriers to readability. -- Note barriers to scannability. -- Note content with the weakest plain language usage. -- Make changes according to the guidelines below. -- Only analyze and edit the specific .md files provided. -- Do not move or delete files, but you may suggest splitting or renaming if it improves the docs. -- Make edits only when they provide meaningful improvements. Do not revise purely for minor aesthetics. -- Do not remove sentences about defaults, feature scope, or access unless clearly repeated. -- Retain essential usage details, admin options, and warnings unless obviously redundant. -- Submit edits as a pull request. +* Read through the article once, noting barriers to readability. +* Note barriers to scannability. +* Note content with the weakest plain language usage. +* Make changes according to the guidelines below. +* Only analyze and edit the specific .md files provided. +* Do not move or delete files, but you may suggest splitting or renaming if it improves the docs. +* Make edits only when they provide meaningful improvements. Do not revise purely for minor aesthetics. +* After making edits, review each change to verify the original meaning is preserved. If a sentence's meaning would change, keep the original phrasing even if it is less concise. +* Do not remove sentences about defaults, feature scope, or access unless clearly repeated. +* Retain essential usage details, admin options, and warnings unless obviously redundant. +* Submit edits as a pull request. ## Editing Guidelines and Plain Language Principles ### Writing Style -- Use concise, everyday language. Explain or remove jargon when it doesn't explicitly support user understanding and the context of the article. -- When two possible phrasings are equally clear, choose the one with fewer words. Brevity directly improves readability. -- Use full terms and not their shortened versions. -- Use active voice and personal pronouns ("you," "your"); favor present tense. -- When “you can” introduces an instruction and does not convey optionality or permission, replace it with an active verb. For example, “You can enable” becomes “Enable”. Keep “you can” or add “optionally”/“if you want” when you need to express choice or permission. -- Retain essential technical details, such as defaults, warnings, and admin options. -- Do not alter the intent of verbs and actions (ex. "navigate" does not necessarily mean "select"). -- Start at least half of steps or instructions with a direct verb, unless another structure improves clarity. -- Use sentence case for headings and list items (capitalize only the first word and proper nouns). -- Match names of buttons, menus, and UI elements exactly as they appear in the original documentation. Do not paraphrase. +* Use concise, everyday language. Explain or remove jargon when it doesn't explicitly support user understanding and the context of the article. +* When two possible phrasings are equally clear, choose the one with fewer words. Brevity directly improves readability. +* Use full terms and not their shortened versions. +* Use active voice and personal pronouns ("you," "your"); favor present tense. +* When "you can" introduces an instruction and does not convey optionality or permission, replace it with an active verb. For example, "You can enable" becomes "Enable". Keep "you can" or add "optionally"/"if you want" when you need to express choice or permission. When in doubt about whether "you can" conveys optionality, keep it. +* Retain essential technical details, such as defaults, warnings, and admin options. +* Do not alter the intent of verbs and actions (ex. "navigate" does not necessarily mean "select"). +* Never change the fundamental meaning of a sentence. Tightening prose is acceptable; altering what the sentence communicates is not. Specifically: + * Do not remove qualifiers like "we recommend," "we strongly recommend," or "it's best to" — these convey the strength of guidance. + * Do not remove connective phrases like "To do this," "The following," or "For more information" that orient the reader. + * Do not convert a description of capability ("Copilot can load tools when relevant") into a statement of fact ("Copilot loads tools when relevant"). + * Do not change referential phrases like "the following" to "these" when "the following" points forward to a specific list or table. +* Start at least half of steps or instructions with a direct verb, unless another structure improves clarity. +* Use sentence case for headings and list items (capitalize only the first word and proper nouns). +* Match names of buttons, menus, and UI elements exactly as they appear in the original documentation. Do not paraphrase. ### Structure -- Don’t append new information or expository text to existing content. -- Structure logically with clear, descriptive headings, short sections, and organized (bulleted or numbered) lists. -- Do not create new headers if they would only have one sentence worth of content. -- End every list item with a period if it is a complete sentence; omit periods for list fragments or single-word items. +* Don't append new information or expository text to existing content. Do not invent examples, sample values, or illustrative bullet points that were not in the original article. +* Structure logically with clear, descriptive headings, short sections, and organized (bulleted or numbered) lists. +* Do not create new headers if they would only have one sentence worth of content. +* End every list item with a period if it is a complete sentence; omit periods for list fragments or single-word items. ### Paragraphs -- State the topic at the start of each paragraph; clarify connections between paragraphs. -- Limit paragraphs to 150 words or fewer. -- Split a paragraph or list item when it includes two topics or steps. +* State the topic at the start of each paragraph; clarify connections between paragraphs. +* Limit paragraphs to 150 words or fewer. +* Split a paragraph or list item when it includes two topics or steps. ### Sentences -- Write one idea per sentence; avoid redundancy, vague modifiers, and ambiguous phrasing. -- Avoid consecutive sentences starting the same way. -- Make sure no more than 25% of sentences contain more than 20 words. -- Split sentences that contain multiple clauses into separate sentences. +* Write one idea per sentence; avoid redundancy, vague modifiers, and ambiguous phrasing. +* Avoid consecutive sentences starting the same way. +* Make sure no more than 25% of sentences contain more than 20 words. +* Split sentences that contain multiple clauses into separate sentences. ## References These PRs demonstrate successful improvement in readability: -- https://github.com/github/docs-internal/pull/59219 -- https://github.com/github/docs-internal/pull/59300 -- https://github.com/github/docs-internal/pull/57154 +* https://github.com/github/docs-internal/pull/59219 +* https://github.com/github/docs-internal/pull/59300 +* https://github.com/github/docs-internal/pull/57154 diff --git a/content/actions/reference/workflows-and-actions/contexts.md b/content/actions/reference/workflows-and-actions/contexts.md index be69fddf55c0..f31ff5971e91 100644 --- a/content/actions/reference/workflows-and-actions/contexts.md +++ b/content/actions/reference/workflows-and-actions/contexts.md @@ -378,15 +378,23 @@ The `job` context contains information about the currently running job. | `job.services..network` | `string` | The ID of the service container network. The runner creates the network used by all containers in a job. | | `job.services..ports` | `object` | The exposed ports of the service container. | | `job.status` | `string` | The current status of the job. Possible values are `success`, `failure`, or `cancelled`. | +| `job.workflow_ref` | `string` | The full ref of the workflow file that defines the current job. For example, `octo-org/octo-repo/.github/workflows/deploy.yml@refs/heads/main`. For jobs defined directly in a workflow file, this is the same as `github.workflow_ref`. For jobs defined in a [AUTOTITLE](/actions/using-workflows/reusing-workflows), this refers to the reusable workflow file. (not available on {% data variables.product.prodname_ghe_server %}) | +| `job.workflow_sha` | `string` | The commit SHA of the workflow file that defines the current job. (not available on {% data variables.product.prodname_ghe_server %}) | +| `job.workflow_repository` | `string` | The `owner/repo` of the repository containing the workflow file that defines the current job. For example, `octo-org/octo-repo`. (not available on {% data variables.product.prodname_ghe_server %}) | +| `job.workflow_file_path` | `string` | The file path of the workflow file that defines the current job, relative to the repository root. For example, `.github/workflows/deploy.yml`. (not available on {% data variables.product.prodname_ghe_server %}) | ### Example contents of the `job` context -This example `job` context uses a PostgreSQL service container with mapped ports. If there are no containers or service containers used in a job, the `job` context only contains the `status` and `check_run_id` properties. +This example `job` context uses a PostgreSQL service container with mapped ports. If there are no containers or service containers used in a job, the `job` context only contains `status`. The `check_run_id` and workflow identity properties (`workflow_ref`, `workflow_sha`, `workflow_repository`, `workflow_file_path`) are not available on {% data variables.product.prodname_ghe_server %}. ```json { "status": "success", - {% ifversion fpt or ghec %}"check_run_id": 51725241954,{% endif %} + "check_run_id": 51725241954, + "workflow_ref": "octo-org/octo-repo/.github/workflows/deploy.yml@refs/heads/main", + "workflow_sha": "abc123def456789abc123def456789abc123def4", + "workflow_repository": "octo-org/octo-repo", + "workflow_file_path": ".github/workflows/deploy.yml", "container": { "network": "github_network_53269bd575974817b43f4733536b200c" }, @@ -427,6 +435,32 @@ jobs: - run: echo "Run tests against Postgres" ``` +### Example usage of `job` context workflow identity + +> [!NOTE] +> The `job.workflow_*` context properties are not available on {% data variables.product.prodname_ghe_server %}. + +This example reusable workflow uses `job.workflow_repository` and `job.workflow_sha` to check out its own source code, rather than the caller's repository. This is useful when a reusable workflow needs to access files co-located with the workflow definition. + +```yaml copy +# In a reusable workflow (e.g., octo-org/shared-workflows/.github/workflows/deploy.yml) +name: Reusable deploy workflow +on: + workflow_call: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: {% data reusables.actions.action-checkout %} + with: + repository: {% raw %}${{ job.workflow_repository }}{% endraw %} + ref: {% raw %}${{ job.workflow_sha }}{% endraw %} + + - run: echo "Deploying from {% raw %}${{ job.workflow_ref }}{% endraw %}" + - run: echo "Workflow file path is {% raw %}${{ job.workflow_file_path }}{% endraw %}" +``` + ## `jobs` context The `jobs` context is only available in reusable workflows, and can only be used to set outputs for a reusable workflow. For more information, see [AUTOTITLE](/actions/using-workflows/reusing-workflows#using-outputs-from-a-reusable-workflow). diff --git a/content/copilot/concepts/billing/billing-for-individuals.md b/content/copilot/concepts/billing/billing-for-individuals.md index 978a61160367..913d2c7e5a89 100644 --- a/content/copilot/concepts/billing/billing-for-individuals.md +++ b/content/copilot/concepts/billing/billing-for-individuals.md @@ -17,7 +17,7 @@ category: --- > [!IMPORTANT] -> {% data reusables.copilot.plans.individual-plans-paused %} If you hit unexpected limits as a result of these changes, you can cancel your Pro or Pro+ subscription and you will not be charged for April usage. Please reach out to [GitHub support](https://support.github.com/) between April 20 and May 20, 2026, for a refund. +> {% data reusables.copilot.plans.individual-plans-paused %} If you hit unexpected limits as a result of these changes, you can cancel your Pro or Pro+ subscription and receive a refund for the time remaining on your current subscription. Please reach out to [GitHub support](https://support.github.com/) between April 20 and May 20, 2026, for a refund. ## Pricing for {% data variables.copilot.copilot_pro_short %} and {% data variables.copilot.copilot_pro_plus_short %} diff --git a/content/copilot/how-tos/configure-custom-instructions/add-repository-instructions.md b/content/copilot/how-tos/configure-custom-instructions-in-your-ide/add-repository-instructions-in-your-ide.md similarity index 62% rename from content/copilot/how-tos/configure-custom-instructions/add-repository-instructions.md rename to content/copilot/how-tos/configure-custom-instructions-in-your-ide/add-repository-instructions-in-your-ide.md index 61f202c0d9dd..a1f81c1adf81 100644 --- a/content/copilot/how-tos/configure-custom-instructions/add-repository-instructions.md +++ b/content/copilot/how-tos/configure-custom-instructions-in-your-ide/add-repository-instructions-in-your-ide.md @@ -1,200 +1,14 @@ --- -title: Adding repository custom instructions for GitHub Copilot -shortTitle: Add repository instructions +title: Adding repository custom instructions for GitHub Copilot in your IDE +shortTitle: Add repository instructions in your IDE intro: 'Create repository custom instructions files that give {% data variables.product.prodname_copilot_short %} additional context on how to understand your project and how to build, test and validate its changes.' versions: feature: copilot contentType: how-tos -redirect_from: - - /copilot/customizing-copilot/adding-custom-instructions-for-github-copilot - - /copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot - - /copilot/how-tos/custom-instructions/adding-repository-custom-instructions-for-github-copilot - - /copilot/how-tos/custom-instructions/add-repository-instructions - - /copilot/how-tos/use-copilot-agents/request-a-code-review/configure-coding-guidelines category: - Configure Copilot --- - - -{% webui %} - -This version of this article is for using repository custom instructions on the {% data variables.product.github %} website. Click the tabs above for information on using custom instructions in other environments. - -{% data reusables.copilot.repository-custom-instructions-about %} - -{% data reusables.copilot.repository-custom-instructions-prerequisites %} - -* For {% data variables.copilot.copilot_code-review_short %}, your personal choice of whether to use custom instructions must be set to enabled. This is enabled by default. See [Enabling or disabling repository custom instructions](#enabling-or-disabling-custom-instructions-for-copilot-code-review) later in this article. - -## Creating custom instructions - -{% data variables.product.prodname_copilot_short %} on {% data variables.product.github %} supports three types of repository custom instructions. For details of which {% data variables.product.prodname_copilot %} features support these types of instructions, see [AUTOTITLE](/copilot/concepts/prompting/response-customization?tool=webui#support-for-repository-custom-instructions). - -* **Repository-wide custom instructions** apply to all requests made in the context of a repository. - - These are specified in a `copilot-instructions.md` file in the `.github` directory of the repository. See [Creating repository-wide custom instructions](#creating-repository-wide-custom-instructions-2). - -* **Path-specific custom instructions** apply to requests made in the context of files that match a specified path. - - These are specified in one or more `NAME.instructions.md` files within or below the `.github/instructions` directory in the repository. See [Creating path-specific custom instructions](#creating-path-specific-custom-instructions-2). - - If the path you specify matches a file that {% data variables.product.prodname_copilot_short %} is working on, and a repository-wide custom instructions file also exists, then the instructions from both files are used. - -* **Agent instructions** are used by AI agents. - - {% data reusables.copilot.custom-instructions-agents %} - - Alternatively, you can use a single `CLAUDE.md` or `GEMINI.md` file stored in the root of the repository. - -## Creating repository-wide custom instructions - -You can create your own custom instructions file from scratch. See [Writing your own copilot-instructions.md file](#writing-your-own-copilot-instructionsmd-file). Alternatively, you can ask {% data variables.copilot.copilot_cloud_agent %} to generate one for you. - -### Asking {% data variables.copilot.copilot_cloud_agent %} to generate a `copilot-instructions.md` file - -1. Navigate to the agents tab at [github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text). - - You can also reach this page by clicking the **{% octicon "copilot" aria-label="Copilot icon" %}** button next to the search bar on any page on {% data variables.product.github %}, then selecting **Agents** from the sidebar. - -1. Using the dropdown menu in the prompt field, select the repository you want {% data variables.product.prodname_copilot_short %} to generate custom instructions for. -1. Copy the following prompt and paste it into the prompt field, customizing it if needed: - - ```markdown copy - Your task is to "onboard" this repository to Copilot cloud agent by adding a .github/copilot-instructions.md file in the repository that contains information describing how a cloud agent seeing it for the first time can work most efficiently. - - You will do this task only one time per repository and doing a good job can SIGNIFICANTLY improve the quality of the agent's work, so take your time, think carefully, and search thoroughly before writing the instructions. - - - - Reduce the likelihood of a cloud agent pull request getting rejected by the user due to - generating code that fails the continuous integration build, fails a validation pipeline, or - having misbehavior. - - Minimize bash command and build failures. - - Allow the agent to complete its task more quickly by minimizing the need for exploration using grep, find, str_replace_editor, and code search tools. - - - - - Instructions must be no longer than 2 pages. - - Instructions must not be task specific. - - - - - Add the following high level details about the codebase to reduce the amount of searching the agent has to do to understand the codebase each time: - - - - A summary of what the repository does. - - High level repository information, such as the size of the repo, the type of the project, the languages, frameworks, or target runtimes in use. - - - Add information about how to build and validate changes so the agent does not need to search and find it each time. - - - - For each of bootstrap, build, test, run, lint, and any other scripted step, document the sequence of steps to take to run it successfully as well as the versions of any runtime or build tools used. - - Each command should be validated by running it to ensure that it works correctly as well as any preconditions and postconditions. - - Try cleaning the repo and environment and running commands in different orders and document errors and misbehavior observed as well as any steps used to mitigate the problem. - - Run the tests and document the order of steps required to run the tests. - - Make a change to the codebase. Document any unexpected build issues as well as the workarounds. - - Document environment setup steps that seem optional but that you have validated are actually required. - - Document the time required for commands that failed due to timing out. - - When you find a sequence of commands that work for a particular purpose, document them in detail. - - Use language to indicate when something should always be done. For example: "always run npm install before building". - - Record any validation steps from documentation. - - - List key facts about the layout and architecture of the codebase to help the agent find where to make changes with minimal searching. - - - - A description of the major architectural elements of the project, including the relative paths to the main project files, the location - of configuration files for linting, compilation, testing, and preferences. - - A description of the checks run prior to check in, including any GitHub workflows, continuous integration builds, or other validation pipelines. - - Document the steps so that the agent can replicate these itself. - - Any explicit validation steps that the agent can consider to have further confidence in its changes. - - Dependencies that aren't obvious from the layout or file structure. - - Finally, fill in any remaining space with detailed lists of the following, in order of priority: the list of files in the repo root, the - contents of the README, the contents of any key source files, the list of files in the next level down of directories, giving priority to the more structurally important and snippets of code from key source files, such as the one containing the main method. - - - - - - Perform a comprehensive inventory of the codebase. Search for and view: - - README.md, CONTRIBUTING.md, and all other documentation files. - - Search the codebase for build steps and indications of workarounds like 'HACK', 'TODO', etc. - - All scripts, particularly those pertaining to build and repo or environment setup. - - All build and actions pipelines. - - All project files. - - All configuration and linting files. - - For each file: - - think: are the contents or the existence of the file information that the cloud agent will need to implement, build, test, validate, or demo a code change? - - If yes: - - Document the command or information in detail. - - Explicitly indicate which commands work and which do not and the order in which commands should be run. - - Document any errors encountered as well as the steps taken to workaround them. - - Document any other steps or information that the agent can use to reduce time spent exploring or trying and failing to run bash commands. - - Finally, explicitly instruct the agent to trust the instructions and only perform a search if the information in the instructions is incomplete or found to be in error. - - - Document any errors encountered as well as the steps taken to work-around them. - -1. Click **{% octicon "paper-airplane" aria-label="Start task" %}** or press Enter. - -{% data variables.product.prodname_copilot_short %} will start a new session, which will appear in the list below the prompt box. {% data variables.product.prodname_copilot_short %} will create a draft pull request, write your custom instructions, push them to the branch, then add you as a reviewer when it has finished, triggering a notification. - -### Writing your own `copilot-instructions.md` file - -1. In the root of your repository, create a file named `.github/copilot-instructions.md`. - - Create the `.github` directory if it does not already exist. - -1. Add natural language instructions to the file, in Markdown format. - - Whitespace between instructions is ignored, so the instructions can be written as a single paragraph, each on a new line, or separated by blank lines for legibility. - -> [!TIP] -> The first time you create a pull request in a given repository with {% data variables.copilot.copilot_cloud_agent %}, {% data variables.product.prodname_copilot_short %} will leave a comment with a link to automatically generate custom instructions for the repository. - -## Creating path-specific custom instructions - -> [!NOTE] -> Currently, on {% data variables.product.prodname_dotcom_the_website %}, path-specific custom instructions are only supported for {% data variables.copilot.copilot_cloud_agent %} and {% data variables.copilot.copilot_code-review_short %}. - -{% data reusables.copilot.custom-instructions-path %} - -{% data reusables.copilot.custom-instructions-note %} - -In {% data variables.copilot.copilot_chat_short %} ([github.com/copilot](https://github.com/copilot)), you can start a conversation that uses repository custom instructions by adding, as an attachment, the repository that contains the instructions file. - -Whenever repository custom instructions are used by {% data variables.copilot.copilot_chat_short %}, the instructions file is added as a reference for the response that's generated. To find out whether repository custom instructions were used, expand the list of references at the top of a chat response in the Chat panel and check whether the `.github/copilot-instructions.md` file is listed. - -![Screenshot of an expanded References list, showing the 'copilot-instructions.md' file highlighted with a dark orange outline.](/assets/images/help/copilot/custom-instructions-ref-in-github.png) - -You can click the reference to open the file. - -> [!NOTE] -> * {% data reusables.copilot.custom-instructions-chat-precedence %} -> * {% data reusables.copilot.custom-instructions-conflict %} - -## Enabling or disabling custom instructions for {% data variables.copilot.copilot_code-review_short %} - -Custom instructions are enabled for {% data variables.copilot.copilot_code-review_short %} by default but you can disable, or re-enable, them in the repository settings on {% data variables.product.prodname_dotcom_the_website %}. This applies to {% data variables.product.prodname_copilot_short %}'s use of custom instructions for all code reviews it performs in this repository. - -{% data reusables.repositories.navigate-to-repo %} -{% data reusables.repositories.sidebar-settings %} -1. In the "Code & automation" section of the sidebar, click **{% octicon "copilot" aria-hidden="true" aria-label="copilot" %} {% data variables.product.prodname_copilot_short %}**, then **Code review**. -1. Toggle the “Use custom instructions when reviewing pull requests” option on or off. - -> [!NOTE] -> {% data reusables.copilot.code-review.custom-instructions-branch %} - -## Further reading - -* [AUTOTITLE](/copilot/reference/custom-instructions-support) -* [AUTOTITLE](/copilot/tutorials/customization-library/custom-instructions)—a curated collection of examples -* [AUTOTITLE](/copilot/tutorials/use-custom-instructions) - -{% endwebui %} - - - {% vscode %} @@ -205,7 +19,7 @@ This version of this article is for using repository custom instructions and pro {% data reusables.copilot.repository-custom-instructions-prerequisites %} -* Custom instructions must be enabled. This feature is enabled by default. See [Enabling or disabling repository custom instructions](#enabling-or-disabling-repository-custom-instructions-1) later in this article. +* Custom instructions must be enabled. This feature is enabled by default. See [Enabling or disabling repository custom instructions](#enabling-or-disabling-repository-custom-instructions) later in this article. ## Creating custom instructions @@ -215,11 +29,11 @@ This version of this article is for using repository custom instructions and pro * **Repository-wide custom instructions**, which apply to all requests made in the context of a repository. - These are specified in a `copilot-instructions.md` file in the `.github` directory of the repository. See [Creating repository-wide custom instructions](#creating-repository-wide-custom-instructions-1). + These are specified in a `copilot-instructions.md` file in the `.github` directory of the repository. See [Creating repository-wide custom instructions](#creating-repository-wide-custom-instructions). * **Path-specific custom instructions**, which apply to requests made in the context of files that match a specified path. - These are specified in one or more `NAME.instructions.md` files within or below the `.github/instructions` directory in the repository. See [Creating path-specific custom instructions](#creating-path-specific-custom-instructions-1). + These are specified in one or more `NAME.instructions.md` files within or below the `.github/instructions` directory in the repository. See [Creating path-specific custom instructions](#creating-path-specific-custom-instructions). If the path you specify matches a file that {% data variables.product.prodname_copilot_short %} is working on, and a repository-wide custom instructions file also exists, then the instructions from both files are used. @@ -324,11 +138,11 @@ This version of this article is for using repository custom instructions and pro * **Repository-wide custom instructions**, which apply to all requests made in the context of a repository. - These are specified in a `copilot-instructions.md` file in the `.github` directory of the repository. See [Creating repository-wide custom instructions](#creating-repository-wide-custom-instructions-2). + These are specified in a `copilot-instructions.md` file in the `.github` directory of the repository. See [Creating repository-wide custom instructions](#creating-repository-wide-custom-instructions-1). * **Path-specific custom instructions**, which apply to requests made in the context of files that match a specified path. - These are specified in one or more `NAME.instructions.md` files within or below the `.github/instructions` directory in the repository. See [Creating path-specific custom instructions](#creating-path-specific-custom-instructions-2). + These are specified in one or more `NAME.instructions.md` files within or below the `.github/instructions` directory in the repository. See [Creating path-specific custom instructions](#creating-path-specific-custom-instructions-1). If the path you specify matches a file that {% data variables.product.prodname_copilot_short %} is working on, and a repository-wide custom instructions file also exists, then the instructions from both files are used. diff --git a/content/copilot/how-tos/configure-custom-instructions/index.md b/content/copilot/how-tos/configure-custom-instructions-in-your-ide/index.md similarity index 66% rename from content/copilot/how-tos/configure-custom-instructions/index.md rename to content/copilot/how-tos/configure-custom-instructions-in-your-ide/index.md index e7003aa1e8af..fc011f1dc7e9 100644 --- a/content/copilot/how-tos/configure-custom-instructions/index.md +++ b/content/copilot/how-tos/configure-custom-instructions-in-your-ide/index.md @@ -5,10 +5,6 @@ intro: 'Learn how to give {% data variables.product.prodname_copilot %} persiste versions: feature: copilot children: - - /add-personal-instructions - - /add-repository-instructions - - /add-organization-instructions -redirect_from: - - /copilot/how-tos/custom-instructions + - /add-repository-instructions-in-your-ide contentType: how-tos --- diff --git a/content/copilot/how-tos/copilot-cli/index.md b/content/copilot/how-tos/copilot-cli/index.md index bb40b56de0c1..2d54e41dc6c9 100644 --- a/content/copilot/how-tos/copilot-cli/index.md +++ b/content/copilot/how-tos/copilot-cli/index.md @@ -25,6 +25,7 @@ children: - /use-copilot-cli-agents - /administer-copilot-cli-for-your-enterprise - /speed-up-task-completion + - /manage-pull-requests - /roll-back-changes - /chronicle - /content/copilot/concepts/agents/copilot-cli/about-copilot-cli diff --git a/content/copilot/how-tos/copilot-cli/manage-pull-requests.md b/content/copilot/how-tos/copilot-cli/manage-pull-requests.md new file mode 100644 index 000000000000..224d98b09525 --- /dev/null +++ b/content/copilot/how-tos/copilot-cli/manage-pull-requests.md @@ -0,0 +1,213 @@ +--- +title: 'Managing pull requests with the /pr command' +shortTitle: Manage pull requests +intro: 'Use the `/pr` slash command to view, create, and fix pull requests directly from {% data variables.copilot.copilot_cli_short %}.' +versions: + feature: copilot +contentType: how-tos +category: + - Author and optimize with Copilot # Copilot discovery page + - Build with Copilot CLI # Copilot CLI bespoke page +docsTeamMetrics: + - copilot-cli +--- + +## Overview + +The `/pr` slash command lets you manage the full pull request lifecycle without leaving your terminal. You can check pull request status, create new pull requests, and fix common issues such as review feedback, merge conflicts, and CI failures. + +## Prerequisite + +You must be working in a Git repository that is hosted on {% data variables.product.prodname_dotcom %}. + +## Subcommands + +The `/pr` slash command has several subcommands that you can use to perform different actions on your pull requests. + +> [!NOTE] +> All `/pr` subcommands relate to the current branch—for example, fixing failing CI checks for the pull request associated with the current branch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Use this subcommandTo do thisRequires an existing PRMay commit and push
/pr or /pr viewShow the status of the pull request for the current branch. Find out moreYesNo
/pr view webOpen the pull request in your browser. Find out moreYesNo
/pr createCreate or update a pull request. Find out moreNoYes
/pr fix feedbackAddress review comments on the pull request. Find out moreYesYes
/pr fix conflictsSync the branch with the base branch and resolve conflicts. Find out moreYesYes
/pr fix ciDiagnose and fix failing CI checks. Find out moreYesYes
/pr fix or /pr fix allRun all three fix phases in order: feedback, conflicts, then CI. Find out moreYesYes
/pr autoCreate a pull request if needed, then loop through all fix phases until all pull request checks are passing. Find out moreNoYes
+ +Subcommands that commit and push changes will prompt you for permission before performing potentially destructive actions, unless you have pre-allowed those tools. For more information, see [AUTOTITLE](/copilot/how-tos/copilot-cli/allowing-tools). + +## Viewing pull request status + +To check the status of the pull request associated with your current branch, enter the following in an interactive session: + +```copilot copy +/pr +``` + +### Opening the pull request in your browser + +If you want to view the pull request on {% data variables.product.prodname_dotcom_the_website %} instead of in the terminal, enter: + +```copilot copy +/pr view web +``` + +This opens the pull request URL in your default browser. + +## Creating a pull request + +To create a pull request from your current branch, enter: + +```copilot copy +/pr create +``` + +{% data variables.product.prodname_copilot_short %} ensures that all local commits are pushed to the remote branch, then creates the pull request. If a pull request template exists in the repository, {% data variables.product.prodname_copilot_short %} follows it when generating the pull request title and description. + +If a pull request already exists for the current branch, `/pr create` updates the existing pull request instead of creating a new one. + +### Adding instructions for pull request creation + +You can append instructions after `/pr create` to guide {% data variables.product.prodname_copilot_short %}. For example: + +```copilot copy +/pr create prefix the PR title 'Project X: ' +``` + +## Fixing review feedback + +To have {% data variables.product.prodname_copilot_short %} read and address review comments on your pull request, enter: + +```copilot copy +/pr fix feedback +``` + +{% data variables.product.prodname_copilot_short %} fetches all review comment threads on the pull request, determines what changes are requested, applies the changes to your codebase, and commits and pushes the fixes. Actionable code change requests are prioritized over conversational comments. + +## Resolving merge conflicts + +To sync your branch with the base branch and resolve any merge conflicts, enter: + +```copilot copy +/pr fix conflicts +``` + +{% data variables.product.prodname_copilot_short %} fetches the latest base branch, syncs your branch, resolves any conflicts, and pushes the result. + +### Choosing a merge strategy + +When resolving conflicts, {% data variables.copilot.copilot_cli_short %} needs to know whether to use a rebase or merge strategy. If you have not configured a preference, {% data variables.product.prodname_copilot_short %} prompts you to choose when you run a command that involves conflict resolution. + +To set a default merge strategy so that you are not prompted each time, add the `mergeStrategy` setting to your configuration file. You can set this in your personal user settings for {% data variables.product.prodname_copilot_short %}, or in the repository settings. + +* **User settings**: Add `"mergeStrategy": "rebase"` or `"mergeStrategy": "merge"` to your user-level configuration file (typically `~/.copilot/config.json`). +* **Repository settings**: Add the same setting to `.github/copilot/settings.json` in your repository root. + +## Fixing CI failures + +To have {% data variables.product.prodname_copilot_short %} diagnose and fix failing CI checks, enter: + +```copilot copy +/pr fix ci +``` + +{% data variables.product.prodname_copilot_short %} identifies the failing CI jobs, analyzes the logs to determine root causes, applies targeted fixes, and pushes them. It then re-checks the CI status and repeats the process until the checks pass or it determines that further progress is not possible. + +If failures are unrelated to your branch changes, {% data variables.product.prodname_copilot_short %} notes this clearly so you can take appropriate action. + +You can append additional context to help {% data variables.product.prodname_copilot_short %} focus on specific failures. For example: + +```copilot copy +/pr fix ci focus on test failures +``` + +## Fixing all issues at once + +To address all outstanding issues on a pull request in a single command, enter: + +```copilot copy +/pr fix +``` + +This runs three phases in order: + +1. **Review feedback** — Addresses all review comments. +1. **Conflicts** — Syncs the branch with the base branch and resolves any conflicts. +1. **CI failures** — Diagnoses and fixes failing CI checks. + +## Automating the full pull request workflow + +To have {% data variables.product.prodname_copilot_short %} manage the entire pull request process from creation to a fully green state, enter: + +```copilot copy +/pr auto +``` + +If no pull request exists for the current branch, {% data variables.product.prodname_copilot_short %} creates one first. It then loops through the fix phases—review feedback, conflicts, and CI—repeating until there are no more review comments, no conflicts, and all CI checks pass. + +You can append instructions to guide the pull request creation. For example: + +```copilot copy +/pr auto include migration notes in the description +``` + +## Further reading + +* [AUTOTITLE](/copilot/how-tos/copilot-cli/allowing-tools) +* [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-command-reference) diff --git a/content/copilot/how-tos/configure-custom-instructions/add-organization-instructions.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-organization-instructions.md similarity index 96% rename from content/copilot/how-tos/configure-custom-instructions/add-organization-instructions.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-organization-instructions.md index c50ec01381c6..1993941357c2 100644 --- a/content/copilot/how-tos/configure-custom-instructions/add-organization-instructions.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-organization-instructions.md @@ -10,6 +10,7 @@ redirect_from: - /copilot/customizing-copilot/adding-organization-custom-instructions-for-github-copilot - /copilot/how-tos/custom-instructions/adding-organization-custom-instructions-for-github-copilot - /copilot/how-tos/custom-instructions/add-organization-instructions + - /copilot/how-tos/configure-custom-instructions/add-organization-instructions contentType: how-tos category: - Configure Copilot diff --git a/content/copilot/how-tos/configure-custom-instructions/add-personal-instructions.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-personal-instructions.md similarity index 73% rename from content/copilot/how-tos/configure-custom-instructions/add-personal-instructions.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-personal-instructions.md index b83a093c0186..d7787645f8c3 100644 --- a/content/copilot/how-tos/configure-custom-instructions/add-personal-instructions.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-personal-instructions.md @@ -8,6 +8,7 @@ redirect_from: - /copilot/customizing-copilot/adding-personal-custom-instructions-for-github-copilot - /copilot/how-tos/custom-instructions/adding-personal-custom-instructions-for-github-copilot - /copilot/how-tos/custom-instructions/add-personal-instructions + - /copilot/how-tos/configure-custom-instructions/add-personal-instructions contentType: how-tos category: - Configure Copilot @@ -15,11 +16,11 @@ category: {% data reusables.copilot.personal-instructions-note %} -You can customize {% data variables.copilot.copilot_chat %} responses in several ways. For an overview, see [AUTOTITLE](/copilot/concepts/about-customizing-github-copilot-chat-responses?tool=webui). +You can layer multiple types of custom instructions to shape {% data variables.copilot.copilot_chat %} responses. For an overview, see [AUTOTITLE](/copilot/concepts/about-customizing-github-copilot-chat-responses?tool=webui). ## About personal custom instructions for {% data variables.copilot.copilot_chat_short %} -Add custom instructions to receive personalized chat responses. Your instructions apply to all your conversations on the {% data variables.product.github %} website. Custom instructions let you specify preferences such as your preferred language or response style. +Personal custom instructions apply to every conversation you have on the {% data variables.product.github %} website, so {% data variables.product.prodname_copilot_short %} always responds in your preferred language, tone, and style. Examples of instructions you can add: @@ -27,13 +28,13 @@ Examples of instructions you can add: * `Use a helpful, collegial tone. Keep explanations brief, but provide enough context to understand the code.` * `Always provide examples in TypeScript.` -> [!NOTE] -> * {% data reusables.copilot.custom-instructions-chat-precedence %} -> * {% data reusables.copilot.custom-instructions-conflict %} +{% data reusables.copilot.custom-instructions-chat-precedence %} + +{% data reusables.copilot.custom-instructions-conflict %} ## Adding personal custom instructions -To add personal custom instructions in {% data variables.copilot.copilot_chat_short %} on {% data variables.product.github %}: +To add personal custom instructions on {% data variables.product.github %}: 1. Open [{% data variables.copilot.copilot_chat_short %}](https://github.com/copilot?ref_product=copilot&ref_type=engagement&ref_style=text). 1. In the bottom left corner, click your profile picture. Then click **{% octicon "note" aria-hidden="true" aria-label="note" %} Personal instructions**. @@ -46,7 +47,7 @@ To add personal custom instructions in {% data variables.copilot.copilot_chat_sh When you select a template, placeholder text appears. Replace placeholders like `{format}` with your preferences. 1. Click **Save**. -Your instructions are now active. They will remain active until you change or remove them. +Your instructions are now active and remain active until you change or remove them. {% note %} diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions.md new file mode 100644 index 000000000000..86dba096a540 --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions.md @@ -0,0 +1,189 @@ +--- +title: Adding repository custom instructions for GitHub Copilot +shortTitle: Add repository instructions +intro: 'Create repository custom instructions files that give {% data variables.product.prodname_copilot_short %} additional context on how to understand your project and how to build, test and validate its changes.' +versions: + feature: copilot +contentType: how-tos +redirect_from: + - /copilot/customizing-copilot/adding-custom-instructions-for-github-copilot + - /copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot + - /copilot/how-tos/custom-instructions/adding-repository-custom-instructions-for-github-copilot + - /copilot/how-tos/custom-instructions/add-repository-instructions + - /copilot/how-tos/use-copilot-agents/request-a-code-review/configure-coding-guidelines + - /copilot/how-tos/configure-custom-instructions/add-repository-instructions +category: + - Configure Copilot +--- + +## Introduction + +Repository custom instructions let you provide {% data variables.product.prodname_copilot_short %} with repository-specific guidance and preferences on {% data variables.product.github %}. To find out how to set up custom instructions in an IDE, see [AUTOTITLE](/copilot/how-tos/configure-custom-instructions-in-your-ide/add-repository-instructions-in-your-ide). For more information about custom instructions, see [AUTOTITLE](/copilot/concepts/prompting/response-customization). + +{% data reusables.copilot.repository-custom-instructions-prerequisites %} + +* For {% data variables.copilot.copilot_code-review_short %}, your personal choice of whether to use custom instructions must be set to enabled. This is enabled by default. See [Enabling or disabling repository custom instructions](#enabling-or-disabling-custom-instructions-for-copilot-code-review) later in this article. + +## Creating custom instructions + +{% data variables.product.prodname_copilot_short %} on {% data variables.product.github %} supports three types of repository custom instructions. For details of which {% data variables.product.prodname_copilot %} features support these types of instructions, see [AUTOTITLE](/copilot/concepts/prompting/response-customization?tool=webui#support-for-repository-custom-instructions). + +* **Repository-wide custom instructions** apply to all requests made in the context of a repository. + + These are specified in a `copilot-instructions.md` file in the `.github` directory of the repository. See [Creating repository-wide custom instructions](#creating-repository-wide-custom-instructions). + +* **Path-specific custom instructions** apply to requests made in the context of files that match a specified path. + + These are specified in one or more `NAME.instructions.md` files within or below the `.github/instructions` directory in the repository. See [Creating path-specific custom instructions](#creating-path-specific-custom-instructions). + + If the path you specify matches a file that {% data variables.product.prodname_copilot_short %} is working on, and a repository-wide custom instructions file also exists, then the instructions from both files are used. + +* **Agent instructions** are used by AI agents. + + {% data reusables.copilot.custom-instructions-agents %} + + Alternatively, you can use a single `CLAUDE.md` or `GEMINI.md` file stored in the root of the repository. + +## Creating repository-wide custom instructions + +You can create your own custom instructions file from scratch. See [Writing your own copilot-instructions.md file](#writing-your-own-copilot-instructionsmd-file). Alternatively, you can ask {% data variables.copilot.copilot_cloud_agent %} to generate one for you. + +### Asking {% data variables.copilot.copilot_cloud_agent %} to generate a `copilot-instructions.md` file + +1. Go to the agents tab at [github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text). + + You can also reach this page by clicking the **{% octicon "copilot" aria-label="Copilot icon" %}** button next to the search bar on any page on {% data variables.product.github %}, then selecting **Agents** from the sidebar. + +1. In the prompt field dropdown, select the repository you want {% data variables.product.prodname_copilot_short %} to generate custom instructions for. +1. Copy the following prompt and paste it into the prompt field, customizing it if needed: + + ```markdown copy + Your task is to "onboard" this repository to Copilot cloud agent by adding a .github/copilot-instructions.md file in the repository that contains information describing how a cloud agent seeing it for the first time can work most efficiently. + + You will do this task only one time per repository and doing a good job can SIGNIFICANTLY improve the quality of the agent's work, so take your time, think carefully, and search thoroughly before writing the instructions. + + + - Reduce the likelihood of a cloud agent pull request getting rejected by the user due to + generating code that fails the continuous integration build, fails a validation pipeline, or + having misbehavior. + - Minimize bash command and build failures. + - Allow the agent to complete its task more quickly by minimizing the need for exploration using grep, find, str_replace_editor, and code search tools. + + + + - Instructions must be no longer than 2 pages. + - Instructions must not be task specific. + + + + + Add the following high level details about the codebase to reduce the amount of searching the agent has to do to understand the codebase each time: + + + - A summary of what the repository does. + - High level repository information, such as the size of the repo, the type of the project, the languages, frameworks, or target runtimes in use. + + + Add information about how to build and validate changes so the agent does not need to search and find it each time. + + + - For each of bootstrap, build, test, run, lint, and any other scripted step, document the sequence of steps to take to run it successfully as well as the versions of any runtime or build tools used. + - Each command should be validated by running it to ensure that it works correctly as well as any preconditions and postconditions. + - Try cleaning the repo and environment and running commands in different orders and document errors and misbehavior observed as well as any steps used to mitigate the problem. + - Run the tests and document the order of steps required to run the tests. + - Make a change to the codebase. Document any unexpected build issues as well as the workarounds. + - Document environment setup steps that seem optional but that you have validated are actually required. + - Document the time required for commands that failed due to timing out. + - When you find a sequence of commands that work for a particular purpose, document them in detail. + - Use language to indicate when something should always be done. For example: "always run npm install before building". + - Record any validation steps from documentation. + + + List key facts about the layout and architecture of the codebase to help the agent find where to make changes with minimal searching. + + + - A description of the major architectural elements of the project, including the relative paths to the main project files, the location + of configuration files for linting, compilation, testing, and preferences. + - A description of the checks run prior to check in, including any GitHub workflows, continuous integration builds, or other validation pipelines. + - Document the steps so that the agent can replicate these itself. + - Any explicit validation steps that the agent can consider to have further confidence in its changes. + - Dependencies that aren't obvious from the layout or file structure. + - Finally, fill in any remaining space with detailed lists of the following, in order of priority: the list of files in the repo root, the + contents of the README, the contents of any key source files, the list of files in the next level down of directories, giving priority to the more structurally important and snippets of code from key source files, such as the one containing the main method. + + + + + - Perform a comprehensive inventory of the codebase. Search for and view: + - README.md, CONTRIBUTING.md, and all other documentation files. + - Search the codebase for build steps and indications of workarounds like 'HACK', 'TODO', etc. + - All scripts, particularly those pertaining to build and repo or environment setup. + - All build and actions pipelines. + - All project files. + - All configuration and linting files. + - For each file: + - think: are the contents or the existence of the file information that the cloud agent will need to implement, build, test, validate, or demo a code change? + - If yes: + - Document the command or information in detail. + - Explicitly indicate which commands work and which do not and the order in which commands should be run. + - Document any errors encountered as well as the steps taken to workaround them. + - Document any other steps or information that the agent can use to reduce time spent exploring or trying and failing to run bash commands. + - Finally, explicitly instruct the agent to trust the instructions and only perform a search if the information in the instructions is incomplete or found to be in error. + + - Document any errors encountered as well as the steps taken to work-around them. + +1. Click **{% octicon "paper-airplane" aria-label="Start task" %}** or press Enter. + +{% data variables.product.prodname_copilot_short %} will start a new session, which will appear in the list below the prompt box. {% data variables.product.prodname_copilot_short %} will create a draft pull request, write your custom instructions, push them to the branch, then add you as a reviewer when finished, triggering a notification. + +### Writing your own `copilot-instructions.md` file + +1. In the root of your repository, create a file named `.github/copilot-instructions.md`. + + Create the `.github` directory if it does not already exist. + +1. Add natural language instructions to the file, in Markdown format. + + Whitespace between instructions is ignored, so the instructions can be written as a single paragraph, each on a new line, or separated by blank lines for legibility. + +> [!TIP] +> The first time you create a pull request in a given repository with {% data variables.copilot.copilot_cloud_agent %}, {% data variables.product.prodname_copilot_short %} will leave a comment with a link to automatically generate custom instructions for the repository. + +## Creating path-specific custom instructions + +> [!NOTE] +> Currently, on {% data variables.product.prodname_dotcom_the_website %}, path-specific custom instructions are only supported for {% data variables.copilot.copilot_cloud_agent %} and {% data variables.copilot.copilot_code-review_short %}. + +{% data reusables.copilot.custom-instructions-path %} + +{% data reusables.copilot.custom-instructions-note %} + +In {% data variables.copilot.copilot_chat_short %} ([github.com/copilot](https://github.com/copilot)), you can start a conversation that uses repository custom instructions by adding, as an attachment, the repository that contains the instructions file. + +Whenever repository custom instructions are used by {% data variables.copilot.copilot_chat_short %}, the instructions file is added as a reference for the response that's generated. To find out whether repository custom instructions were used, expand the list of references at the top of a chat response in the Chat panel and check whether the `.github/copilot-instructions.md` file is listed. + +![Screenshot of an expanded References list, showing the 'copilot-instructions.md' file highlighted with a dark orange outline.](/assets/images/help/copilot/custom-instructions-ref-in-github.png) + +You can click the reference to open the file. + +> [!NOTE] +> * {% data reusables.copilot.custom-instructions-chat-precedence %} +> * {% data reusables.copilot.custom-instructions-conflict %} + +## Enabling or disabling custom instructions for {% data variables.copilot.copilot_code-review_short %} + +Custom instructions are enabled for {% data variables.copilot.copilot_code-review_short %} by default but you can disable, or re-enable, them in the repository settings on {% data variables.product.prodname_dotcom_the_website %}. This applies to {% data variables.product.prodname_copilot_short %}'s use of custom instructions for all code reviews it performs in this repository. + +{% data reusables.repositories.navigate-to-repo %} +{% data reusables.repositories.sidebar-settings %} +1. In the "Code & automation" section of the sidebar, click **{% octicon "copilot" aria-hidden="true" aria-label="copilot" %} {% data variables.product.prodname_copilot_short %}**, then **Code review**. +1. Toggle the “Use custom instructions when reviewing pull requests” option on or off. + +> [!NOTE] +> {% data reusables.copilot.code-review.custom-instructions-branch %} + +## Further reading + +* [AUTOTITLE](/copilot/reference/custom-instructions-support) +* [AUTOTITLE](/copilot/tutorials/customization-library/custom-instructions)—a curated collection of examples +* [AUTOTITLE](/copilot/tutorials/use-custom-instructions) diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/index.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/index.md new file mode 100644 index 000000000000..0be9ff003c2b --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/index.md @@ -0,0 +1,15 @@ +--- +title: 'Add custom instructions for {% data variables.product.prodname_copilot_short %}' +shortTitle: Add custom instructions +intro: 'Give {% data variables.product.prodname_copilot %} persistent instructions to customize responses according to your needs.' +versions: + feature: copilot +children: + - /add-personal-instructions + - /add-repository-instructions + - /add-organization-instructions +redirect_from: + - /copilot/how-tos/configure-custom-instructions + - /copilot/how-tos/custom-instructions +contentType: how-tos +--- diff --git a/content/copilot/how-tos/provide-context/use-copilot-spaces/collaborate-with-others.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/collaborate-with-others.md similarity index 88% rename from content/copilot/how-tos/provide-context/use-copilot-spaces/collaborate-with-others.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/collaborate-with-others.md index 4829b4cf3bd6..13c2871b864b 100644 --- a/content/copilot/how-tos/provide-context/use-copilot-spaces/collaborate-with-others.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/collaborate-with-others.md @@ -1,7 +1,7 @@ --- title: Collaborating with others using GitHub Copilot Spaces shortTitle: Collaborate with others -intro: 'Learn how to share {% data variables.copilot.copilot_spaces %} to support collaboration and knowledge sharing.' +intro: 'Share {% data variables.copilot.copilot_spaces %} to support collaboration and knowledge sharing.' permissions: 'Anyone with a {% data variables.product.prodname_copilot_short %} license can use {% data variables.copilot.copilot_spaces_short %}.' versions: feature: copilot @@ -11,6 +11,7 @@ redirect_from: - /copilot/how-tos/context/copilot-spaces/collaborate-with-your-team - /copilot/how-tos/context/use-copilot-spaces/collaborate-with-your-team - /copilot/how-tos/provide-context/use-copilot-spaces/collaborate-with-your-team + - /copilot/how-tos/provide-context/use-copilot-spaces/collaborate-with-others contentType: how-tos category: - Author and optimize with Copilot @@ -29,7 +30,7 @@ category: * **System knowledge**: Create a space for a complex system or workflow (like authentication or CI pipelines) that other people can reference. * **Style guides or review checklists**: Document standards and examples in a space that {% data variables.product.prodname_copilot_short %} can reference when suggesting changes. -For example, a subject matter expert creates a space called “Accessibility Reviews” that includes your team’s internal accessibility checklist, product guidelines, and WCAG documentation. Developers can ask {% data variables.product.prodname_copilot_short %} questions directly in the space to ensure they're following the latest guidelines in their work. +For example, a subject matter expert creates a space called "Accessibility Reviews" that includes your team's internal accessibility checklist, product guidelines, and WCAG documentation. Developers can ask {% data variables.product.prodname_copilot_short %} questions directly in the space to ensure they're following the latest guidelines in their work. ## Sharing {% data variables.copilot.copilot_spaces_short %} @@ -41,7 +42,7 @@ Organization-owned spaces can be shared with other organization members, and you Alternatively, you can choose to grant "No access" to organization members, and keep the space hidden. -To share a organization-owned space with others: +To share an organization-owned space with others: 1. In the top right corner of the space, click **{% octicon "share" aria-hidden="true" aria-label="share" %}**. 1. To add specific users or teams, search for them with the search bar, then choose a role for the people you added. diff --git a/content/copilot/how-tos/provide-context/use-copilot-spaces/create-copilot-spaces.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/create-copilot-spaces.md similarity index 80% rename from content/copilot/how-tos/provide-context/use-copilot-spaces/create-copilot-spaces.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/create-copilot-spaces.md index 057e19285cea..a78119218fba 100644 --- a/content/copilot/how-tos/provide-context/use-copilot-spaces/create-copilot-spaces.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/create-copilot-spaces.md @@ -11,20 +11,19 @@ redirect_from: - /copilot/how-tos/context/copilot-spaces/creating-and-using-copilot-spaces - /copilot/how-tos/context/copilot-spaces/create-and-use-copilot-spaces - /copilot/how-tos/context/use-copilot-spaces/create-and-use-copilot-spaces + - /copilot/how-tos/provide-context/use-copilot-spaces/create-copilot-spaces contentType: how-tos category: - Author and optimize with Copilot --- -For an overview of {% data variables.copilot.copilot_spaces %}, see [AUTOTITLE](/copilot/concepts/about-organizing-and-sharing-context-with-copilot-spaces). - ## Creating a space 1. To create a space, go to [https://github.com/copilot/spaces](https://github.com/copilot/spaces?ref_product=copilot&ref_type=engagement&ref_style=text), and click **Create space**. 1. Give your space a name. 1. Choose whether the space is owned by you or by an organization you belong to. Organization-owned {% data variables.copilot.copilot_spaces_short %} can be shared using {% data variables.product.github %}’s built-in permission model. 1. Click **Create Space**. -1. Optionally, once you are in the space, under the space name, add a description. This does not affect the responses {% data variables.product.prodname_copilot_short %} gives in the space, but it can help others understand the context of the space. +1. Optionally, under the space name, add a description. The description does not affect {% data variables.product.prodname_copilot_short %}'s responses, but helps others understand the purpose of the space. >[!NOTE] You can change the name and description of your space at any time by hovering over them and clicking **{% octicon "pencil" aria-hidden="true" aria-label="pencil" %}**. @@ -51,9 +50,9 @@ You can add two types of context to your space: When adding sources to your space, you can choose to attach entire repositories or individual files. Understanding how each option works can help you get the best results from {% data variables.product.prodname_copilot_short %}. -* **Attach a repository**: When you attach a repository, {% data variables.product.prodname_copilot_short %} doesn't load the entire project into memory. Instead, it searches the repository and retrieves only the most relevant content needed to answer your question. This is recommended for large-scale use cases (for example, answering questions across all documentation in a repository). +* **Attach a repository**: When you attach a repository, {% data variables.product.prodname_copilot_short %} doesn't load the entire project into memory. Instead, it searches the repository and retrieves only the most relevant content for your question. This is best for large-scale use cases, such as answering questions across all documentation in a repository. -* **Attach individual files**: When you attach a file, its full contents are loaded into {% data variables.product.prodname_copilot_short %}'s context window and considered for every query in that space. This is best when you want {% data variables.product.prodname_copilot_short %} to consistently prioritize a specific document or small set of files. +* **Attach individual files**: When you attach a file, its full contents are loaded into {% data variables.product.prodname_copilot_short %}'s context window and considered for every query in that space. This is best when you want {% data variables.product.prodname_copilot_short %} to consistently prioritize a specific document or a small set of files. ## Adding context as you're working @@ -67,6 +66,7 @@ You can add files to a space directly from the code view on {% data variables.pr ## Next steps -* To learn more about using {% data variables.copilot.copilot_spaces_short %} in {% data variables.product.github %} and your IDE, see [AUTOTITLE](/copilot/how-tos/provide-context/use-copilot-spaces/use-copilot-spaces). -* To learn more about how to use {% data variables.copilot.copilot_spaces_short %} to help you with development work, see [AUTOTITLE](/copilot/using-github-copilot/copilot-spaces/speeding-up-development-work-with-copilot-spaces). -* To learn how to share your space with your team, see [AUTOTITLE](/copilot/using-github-copilot/copilot-spaces/collaborating-with-your-team-using-copilot-spaces). +* For an overview of {% data variables.copilot.copilot_spaces %}, see [AUTOTITLE](/copilot/concepts/about-organizing-and-sharing-context-with-copilot-spaces). +* To use {% data variables.copilot.copilot_spaces_short %} in {% data variables.product.github %} and your IDE, see [AUTOTITLE](/copilot/how-tos/provide-context/use-copilot-spaces/use-copilot-spaces). +* To speed up development work with {% data variables.copilot.copilot_spaces_short %}, see [AUTOTITLE](/copilot/using-github-copilot/copilot-spaces/speeding-up-development-work-with-copilot-spaces). +* To share your space with your team, see [AUTOTITLE](/copilot/using-github-copilot/copilot-spaces/collaborating-with-your-team-using-copilot-spaces). diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/index.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/index.md new file mode 100644 index 000000000000..3fe87c543f1a --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/index.md @@ -0,0 +1,11 @@ +--- +title: '{% data variables.copilot.copilot_spaces %}' +shortTitle: '{% data variables.copilot.copilot_spaces_short %}' +intro: 'Organize and centralize relevant content into {% data variables.copilot.copilot_spaces_short %} that ground {% data variables.product.prodname_copilot_short %}''s responses in the right context for a specific task.' +versions: + feature: copilot +children: + - /create-copilot-spaces + - /collaborate-with-others +contentType: how-tos +--- diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/add-skills.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/add-skills.md similarity index 95% rename from content/copilot/how-tos/use-copilot-agents/cloud-agent/add-skills.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/add-skills.md index 7417748a1112..38acf8769668 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/add-skills.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/add-skills.md @@ -12,6 +12,7 @@ category: redirect_from: - /copilot/how-tos/use-copilot-agents/coding-agent/create-skills - /copilot/how-tos/use-copilot-agents/cloud-agent/create-skills + - /copilot/how-tos/use-copilot-agents/cloud-agent/add-skills --- > [!NOTE] diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/create-custom-agents.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/create-custom-agents.md new file mode 100644 index 000000000000..11247c57b57f --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/create-custom-agents.md @@ -0,0 +1,51 @@ +--- +title: Creating custom agents for {% data variables.copilot.copilot_cloud_agent %} +shortTitle: Create custom agents +intro: You can create specialized agents with tailored expertise for specific development tasks. +product: '{% data reusables.gated-features.copilot-cloud-agent %}
Sign up for {% data variables.product.prodname_copilot_short %} {% octicon "link-external" height:16 %}' +versions: + feature: copilot +category: + - Configure Copilot + - Author and optimize with Copilot +contentType: how-tos +redirect_from: + - /copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents + - /copilot/how-tos/use-copilot-agents/cloud-agent/create-custom-agents +--- + +{% data variables.copilot.custom_agents_caps_short %} allow you to tailor {% data variables.product.prodname_copilot_short %}'s expertise for specific tasks. For a conceptual overview of {% data variables.copilot.custom_agents_short %}, see [AUTOTITLE](/copilot/concepts/agents/cloud-agent/about-custom-agents). + +{% data reusables.copilot.custom-agents-ide-preview %} + +## Creating a {% data variables.copilot.copilot_custom_agent_short %} profile in a repository on {% data variables.product.github %} + +1. Go to the agents tab at [https://github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text). + +1. Using the dropdown menu in the prompt box, select the repository you want to create the {% data variables.copilot.copilot_custom_agent_short %} profile in. + + > [!NOTE] + > Organization and enterprise owners can create organization and enterprise-level {% data variables.copilot.custom_agents_short %} in a `.github-private` repository that are available across all repositories within their organization or enterprise. For more information, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/prepare-for-custom-agents) and [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-organization/prepare-for-custom-agents). + +1. Optionally, select the branch you want to create the {% data variables.copilot.agent_profile %} in. The default is the main branch. +1. Click {% octicon "copilot" aria-label="Select a custom agent" %}, then click **{% octicon "plus" aria-label="Plus button" %} Create an agent**. This will open a template agent profile called `my-agent.agent.md` in the `.github/agents` directory of your target repository. +1. If you are creating an organization or enterprise-level {% data variables.copilot.copilot_custom_agent_short %}, delete the `.github/` portion of the file path to move your template to the root `agents` directory. +1. Edit the filename (the text before `.agent.md`), selecting a unique, descriptive name that identifies the agent's purpose. Note that the filename may only contain the following characters: `.`, `-`, `_`, `a-z`, `A-Z`, `0-9`. +1. Configure the {% data variables.copilot.agent_profile %}, including the name, description, tools, and prompts. For more information on what the {% data variables.copilot.agent_profile %} can include, see [Configuring an {% data variables.copilot.agent_profile %}](#configuring-an-agent-profile). +1. Commit the file to the repository and merge it into the default branch. Go back to the agents tab and refresh the page if needed. Your {% data variables.copilot.copilot_custom_agent_short %} will now appear in the dropdown when you click {% octicon "copilot" aria-hidden="true" aria-label="copilot" %} in the prompt box. + +## Configuring an {% data variables.copilot.agent_profile %} + +{% data reusables.copilot.custom-agents-configuring-profile %} + +## Example {% data variables.copilot.agent_profiles %} + +{% data reusables.copilot.custom-agents-example-profiles %} + +## Using {% data variables.copilot.custom_agents_short %} + +{% data reusables.copilot.custom-agents-using %} + +## Next steps + +{% data reusables.copilot.custom-agents-next-steps %} diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-environment.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-environment.md similarity index 95% rename from content/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-environment.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-environment.md index 345cfa573aa7..17dab87bb29b 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-environment.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-environment.md @@ -1,8 +1,7 @@ --- -title: Customizing the development environment for GitHub Copilot cloud agent +title: Configure the development environment shortTitle: Customize the agent environment -allowTitleToDifferFromFilename: true -intro: 'Learn how to customize {% data variables.product.prodname_copilot %}''s development environment with additional tools.' +intro: 'Pre-install tools and dependencies so {% data variables.copilot.copilot_cloud_agent %} can build, test, and validate changes reliably.' versions: feature: copilot redirect_from: @@ -12,6 +11,7 @@ redirect_from: - /copilot/how-tos/agents/copilot-coding-agent/customizing-the-development-environment-for-copilot-coding-agent - /copilot/how-tos/agents/copilot-coding-agent/customize-the-agent-environment - /copilot/how-tos/agents/coding-agent/customize-the-agent-environment + - /copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-environment contentType: how-tos category: - Configure Copilot @@ -174,7 +174,7 @@ We recommend that you only use {% data variables.copilot.copilot_cloud_agent %} By default, {% data variables.product.prodname_copilot_short %} uses an Ubuntu Linux-based development environment. -You may want to use a Windows development environment if you're building software for Windows or your repository uses a Windows-based toolchain so {% data variables.product.prodname_copilot_short %} can build your project, run tests and validate its work. +You may want to use a Windows development environment if you're building software for Windows or your repository uses a Windows-based toolchain, so {% data variables.product.prodname_copilot_short %} can build your project, run tests, and validate its work. {% data variables.copilot.copilot_cloud_agent %}'s integrated firewall is not compatible with Windows, so we recommend that you only use self-hosted runners or larger {% data variables.product.prodname_dotcom %}-hosted runners with Azure private networking where you can implement your own network controls. For more information on runners with Azure private networking, see [AUTOTITLE](/admin/configuring-settings/configuring-private-networking-for-hosted-compute-products/about-azure-private-networking-for-github-hosted-runners-in-your-enterprise). @@ -204,7 +204,7 @@ jobs: You may want to set environment variables in {% data variables.product.prodname_copilot_short %}'s environment to configure or authenticate tools or dependencies that it has access to. -To set an environment variable for {% data variables.product.prodname_copilot_short %}, create a {% data variables.product.prodname_actions %} variable or secret in the `copilot` environment. If the value contains sensitive information, for example a password or API key, it's best to use a {% data variables.product.prodname_actions %} secret. +You may want to set an environment variable for {% data variables.product.prodname_copilot_short %}, create a {% data variables.product.prodname_actions %} variable or secret in the `copilot` environment. If the value contains sensitive information, for example a password or API key, it's best to use a {% data variables.product.prodname_actions %} secret. {% data reusables.repositories.navigate-to-repo %} {% data reusables.repositories.sidebar-settings %} diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-firewall.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-firewall.md similarity index 90% rename from content/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-firewall.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-firewall.md index daa3b75f5a09..f136807a242b 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-firewall.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/customize-the-agent-firewall.md @@ -11,6 +11,7 @@ redirect_from: - /copilot/how-tos/agents/copilot-coding-agent/customizing-or-disabling-the-firewall-for-copilot-coding-agent - /copilot/how-tos/agents/copilot-coding-agent/customize-the-agent-firewall - /copilot/how-tos/agents/coding-agent/customize-the-agent-firewall + - /copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-firewall contentType: how-tos category: - Configure Copilot @@ -23,11 +24,11 @@ category: By default, {% data variables.product.prodname_copilot_short %}'s access to the internet is limited by a firewall. -Limiting access to the internet helps to manage data exfiltration risks, where surprising behavior from {% data variables.product.prodname_copilot_short %}, or malicious instructions given to it, could lead to code or other sensitive information being leaked to remote locations. +Limiting internet access helps manage data exfiltration risks. Unexpected behavior from {% data variables.product.prodname_copilot_short %}, or malicious instructions, could lead to code or other sensitive information being leaked to remote locations. The firewall always allows access to a number of hosts that {% data variables.product.prodname_copilot_short %} uses to interact with {% data variables.product.github %}. By default, a recommended allowlist is also enabled to allow the agent to download dependencies. -If {% data variables.product.prodname_copilot_short %} tries to make a request which is blocked by the firewall, a warning is added to the pull request body (if {% data variables.product.prodname_copilot_short %} is creating a pull request for the first time) or to a comment (if {% data variables.product.prodname_copilot_short %} is responding to a pull request comment). The warning shows the blocked address and the command that tried to make the request. +If {% data variables.product.prodname_copilot_short %} tries to make a request which is blocked by the firewall, a warning is added to the pull request body (for new pull requests) or to a comment (for existing pull requests). The warning shows the blocked address and the command that tried to make the request. ![Screenshot of a warning from {% data variables.product.prodname_copilot_short %} about being blocked by the firewall.](/assets/images/help/copilot/cloud-agent/firewall-warning.png) @@ -39,7 +40,7 @@ The agent firewall has important limitations that affect its security coverage. * **Only applies within the {% data variables.product.prodname_actions %} appliance**: The firewall only operates within the {% data variables.product.prodname_actions %} appliance environment. It does not apply to processes running outside of this environment. * **Bypass potential**: Sophisticated attacks may bypass the firewall, potentially allowing unauthorized network access and data exfiltration. -These limitations mean that the firewall provides a layer of protection for common scenarios, but should not be considered a comprehensive security solution. +These limitations mean that the firewall provides protection for common scenarios, but should not be considered a comprehensive security solution. ## Understanding the recommended firewall allowlist diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/extend-cloud-agent-with-mcp.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/extend-cloud-agent-with-mcp.md similarity index 97% rename from content/copilot/how-tos/use-copilot-agents/cloud-agent/extend-cloud-agent-with-mcp.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/extend-cloud-agent-with-mcp.md index 74dd25e29fca..a8220aea2514 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/extend-cloud-agent-with-mcp.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/extend-cloud-agent-with-mcp.md @@ -1,8 +1,7 @@ --- -title: Extending GitHub Copilot cloud agent with the Model Context Protocol (MCP) +title: Connect agents to external tools shortTitle: Extend cloud agent with MCP -allowTitleToDifferFromFilename: true -intro: 'Learn how to use the Model Context Protocol (MCP) to extend the capabilities of {% data variables.copilot.copilot_cloud_agent %}.' +intro: 'Connect {% data variables.copilot.copilot_cloud_agent %} to external tools and data sources through the Model Context Protocol (MCP).' versions: feature: copilot redirect_from: @@ -14,6 +13,7 @@ redirect_from: - /copilot/how-tos/agents/copilot-coding-agent/extending-copilot-coding-agent-with-mcp - /copilot/how-tos/agents/copilot-coding-agent/extend-coding-agent-with-mcp - /copilot/how-tos/agents/coding-agent/extend-coding-agent-with-mcp + - /copilot/how-tos/use-copilot-agents/cloud-agent/extend-cloud-agent-with-mcp contentType: how-tos category: - Integrate Copilot with your tools @@ -92,7 +92,7 @@ The configuration object can contain the following keys: * A substitution reference to a secret or variable in your {% data variables.product.prodname_copilot_short %} environment, such as `$COPILOT_MCP_API_KEY` or `${COPILOT_MCP_API_KEY}`. Referenced names must start with `COPILOT_MCP_`. * A literal string value. -Note that all `string` and `string[]` fields besides `tools` & `type` support substitution with a variable or secret you have configured in your {% data variables.product.prodname_copilot_short %} environment. +Note that all `string` and `string[]` fields besides `tools` and `type` support substitution with a variable or secret you have configured in your {% data variables.product.prodname_copilot_short %} environment. ### Variable substitution @@ -107,7 +107,6 @@ The following syntax patterns are supported for referencing environment variable ## Example configurations The examples below show MCP server configurations for different providers. - * [Sentry](#example-sentry) * [Notion](#example-notion) * [Azure](#example-azure) diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/index.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/index.md new file mode 100644 index 000000000000..37b77c9e157b --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/index.md @@ -0,0 +1,16 @@ +--- +title: 'Customize {% data variables.copilot.copilot_cloud_agent %}' +shortTitle: 'Customize {% data variables.copilot.copilot_cloud_agent_short %}' +intro: 'Create specialized agents with tailored expertise and extend their capabilities for {% data variables.copilot.copilot_cloud_agent %}.' +versions: + feature: copilot +children: + - /create-custom-agents + - /add-skills + - /extend-cloud-agent-with-mcp + - /use-hooks + - /customize-the-agent-environment + - /customize-the-agent-firewall + - /test-custom-agents +contentType: how-tos +--- diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/test-custom-agents.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/test-custom-agents.md similarity index 94% rename from content/copilot/how-tos/use-copilot-agents/cloud-agent/test-custom-agents.md rename to content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/test-custom-agents.md index e5b892897fb9..95cc1cdb18fe 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/test-custom-agents.md +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/test-custom-agents.md @@ -10,6 +10,7 @@ category: - Manage Copilot for a team redirect_from: - /copilot/how-tos/use-copilot-agents/coding-agent/test-custom-agents + - /copilot/how-tos/use-copilot-agents/cloud-agent/test-custom-agents --- {% data reusables.copilot.custom-agents-preview-note %} @@ -30,7 +31,7 @@ Before you can test a {% data variables.copilot.copilot_custom_agent_short %}, y ## 2. Test your {% data variables.copilot.copilot_custom_agent_short %} -1. Navigate to the agents tab at [https://github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text). +1. Go to the agents tab at [https://github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text). 1. Using the dropdown menu in the prompt box, select your `.github-private` repository. 1. Select {% octicon "copilot" aria-label="Select a custom agent" %}, then click your test agent. 1. To test your {% data variables.copilot.copilot_custom_agent_short %}, send {% data variables.product.prodname_copilot_short %} a prompt. @@ -46,4 +47,4 @@ Before you can test a {% data variables.copilot.copilot_custom_agent_short %}, y To monitor the usage of {% data variables.copilot.custom_agents_short %} in your organization, filter your organization's audit log by `actor:Copilot`. See [AUTOTITLE](/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/reviewing-the-audit-log-for-your-organization). -To monitor the usage of {% data variables.copilot.custom_agents_short %} in your enterprise, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/monitor-agentic-activity). +To monitor the usage of {% data variables.copilot.custom_agents_short %} in your enterprise, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/monitor-agentic-activity). \ No newline at end of file diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/use-hooks.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/use-hooks.md new file mode 100644 index 000000000000..bbbf6e24174a --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/use-hooks.md @@ -0,0 +1,30 @@ +--- +title: Customize agent workflows with hooks +shortTitle: Use hooks +intro: 'Run automated checks—like linting, formatting, or security scans—at key points during agent execution to enforce quality standards.' +versions: + feature: copilot +contentType: how-tos +category: + - Configure Copilot +redirect_from: + - /copilot/how-tos/use-copilot-agents/coding-agent/use-hooks + - /copilot/how-tos/use-copilot-agents/cloud-agent/use-hooks +--- + +{% data reusables.copilot.cloud-agent.hooks-intro %} + +## Creating a hook in a repository on {% data variables.product.github %} + +{% data reusables.copilot.cloud-agent.create-hooks-instructions %} + +## Troubleshooting + +{% data reusables.copilot.cloud-agent.troubleshoot-hooks %} + +## Further reading + +* [AUTOTITLE](/copilot/reference/hooks-configuration) +* [AUTOTITLE](/copilot/concepts/agents/cloud-agent/about-cloud-agent) +* [AUTOTITLE](/copilot/concepts/agents/about-copilot-cli) +* [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-environment) diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-copilot-overview.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-copilot-overview.md new file mode 100644 index 000000000000..94e0c6ff4317 --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/customize-copilot-overview.md @@ -0,0 +1,94 @@ +--- +title: 'Customize {% data variables.product.prodname_copilot_short %} for your project' +shortTitle: Customize {% data variables.product.prodname_copilot_short %} overview +intro: 'Set up custom instructions, create a specialized agent, and organize project context on {% data variables.product.github %}.' +versions: + feature: copilot +contentType: how-tos +allowTitleToDifferFromFilename: true +--- + +This quickstart walks you through customizing {% data variables.product.prodname_copilot %} for a repository. By the end, {% data variables.product.prodname_copilot_short %} will know your project's conventions, have a specialized agent for common tasks, and have curated project context. + +**Scenario:** You work on a team's web application repository with an established test suite, coding conventions, and active issues. You want {% data variables.product.prodname_copilot_short %} to work effectively with the codebase from day one. + +## Prerequisites + +* A {% data variables.product.prodname_copilot_short %} plan that includes {% data variables.copilot.copilot_cloud_agent %} ({% data variables.copilot.copilot_pro_plus %}, {% data variables.copilot.copilot_business_short %}, or {% data variables.copilot.copilot_enterprise_short %}). For more information, see [AUTOTITLE](/copilot/about-github-copilot/subscription-plans-for-github-copilot). +* {% data variables.copilot.copilot_cloud_agent_short_cap_c %} enabled for your organization or account. For more information, see [AUTOTITLE](/copilot/concepts/agents/cloud-agent/access-management). +* Write access to a {% data variables.product.github %} repository. + +## Step 1: Teach {% data variables.product.prodname_copilot_short %} your project's conventions + +Repository custom instructions give {% data variables.product.prodname_copilot_short %} persistent context about your project—its structure, coding standards, and how to build and test code. Every {% data variables.product.prodname_copilot_short %} interaction in the repository uses these instructions automatically. + +Ask {% data variables.copilot.copilot_cloud_agent %} to generate a `copilot-instructions.md` file: + +1. Go to [github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text). +1. Select your repository from the dropdown menu in the prompt field. +1. Enter the following prompt: + + ```text copy + Onboard this repository to Copilot cloud agent by adding a + .github/copilot-instructions.md file. Include information about project + structure, coding conventions, the test framework, and how to build and + run the project. + ``` + +1. Review the generated file and merge the pull request. + +{% data variables.product.prodname_copilot_short %} now understands your project's conventions across chat, code review, and agent sessions. See [AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions). + +## Step 2: Create a specialized agent + +{% data variables.copilot.custom_agents_caps_short %} let you create focused assistants for recurring tasks. In this example, create an agent that diagnoses and fixes bugs. + +1. Go to [github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text) and select your repository. +1. In the prompt field, click {% octicon "copilot" aria-label="Select a custom agent" %}. Then click **{% octicon "plus" aria-label="Plus button" %} Create a custom agent**. +1. Rename the file to `bug-fixer.agent.md`. +1. Replace the template content with: + + ```yaml copy + --- + name: Bug Fixer + description: Diagnoses and fixes bugs reported in GitHub issues. + tools: + - read + - edit + - terminal + - search + --- + + You are a bug-fixing specialist. When given a bug report or issue: + + 1. Reproduce the bug by writing a failing test. + 2. Identify the root cause. + 3. Fix the code. + 4. Verify the fix passes the test and doesn't break existing tests. + + Always follow the project's testing conventions and coding standards. + ``` + +1. Commit the file and merge it into the default branch. + +Your bug-fixer agent now appears in the agents dropdown on the agents tab. Select it before pasting an issue URL to start a focused debugging session. See [AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/create-custom-agents). + +## Step 3: Organize project context with a space + +{% data variables.copilot.copilot_spaces %} let you curate the exact context {% data variables.product.prodname_copilot_short %} needs for a specific area of your project. Answers are grounded in relevant files, issues, and documentation. + +1. Go to [github.com/copilot/spaces](https://github.com/copilot/spaces?ref_product=copilot&ref_type=engagement&ref_style=text) and click **Create space**. +1. Name the space (for example, "API Architecture") and choose an owner. +1. Click **{% octicon "plus" aria-hidden="true" aria-label="plus" %} Add sources**, then add context that's relevant to your project: + * **{% octicon "file-code" aria-hidden="true" aria-label="file-code" %} Add files and repositories** — Add architecture docs, API schemas, or key configuration files. + * **{% octicon "link" aria-hidden="true" aria-label="link" %} Link files, pull requests, and issues** — Paste URLs for active issues or design discussions. +1. In the space's chat, ask a question like: "What patterns does our API use for error handling?" + +{% data variables.product.prodname_copilot_short %} answers using only the context you've curated. See [AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/create-copilot-spaces). + +## Next steps + +* **[AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-personal-instructions)** — Set personal preferences that apply across all your repositories. +* **[AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/add-skills)** — Add new capabilities to your agents. +* **[AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/extend-cloud-agent-with-mcp)** — Connect agents to external tools and services. +* **[AUTOTITLE](/copilot/how-tos/copilot-on-github/customize-copilot/copilot-spaces/collaborate-with-others)** — Share your spaces with teammates. diff --git a/content/copilot/how-tos/copilot-on-github/customize-copilot/index.md b/content/copilot/how-tos/copilot-on-github/customize-copilot/index.md new file mode 100644 index 000000000000..2c37f334c0cd --- /dev/null +++ b/content/copilot/how-tos/copilot-on-github/customize-copilot/index.md @@ -0,0 +1,13 @@ +--- +title: 'Customize {% data variables.product.prodname_copilot_short %}' +shortTitle: Customize {% data variables.product.prodname_copilot_short %} +intro: 'Customize {% data variables.product.prodname_copilot %} to fit your needs and get better results.' +versions: + feature: copilot +children: + - /customize-copilot-overview + - /add-custom-instructions + - /customize-cloud-agent + - /copilot-spaces +contentType: how-tos +--- diff --git a/content/copilot/how-tos/copilot-on-github/index.md b/content/copilot/how-tos/copilot-on-github/index.md index 3079db935f99..baff5c9ec73e 100644 --- a/content/copilot/how-tos/copilot-on-github/index.md +++ b/content/copilot/how-tos/copilot-on-github/index.md @@ -7,6 +7,7 @@ versions: children: - /set-up-copilot - /chat-with-copilot + - /customize-copilot - /copilot-for-github-tasks - /use-copilot-agents contentType: how-tos diff --git a/content/copilot/how-tos/index.md b/content/copilot/how-tos/index.md index 394268b11e79..c821202df6cc 100644 --- a/content/copilot/how-tos/index.md +++ b/content/copilot/how-tos/index.md @@ -14,7 +14,7 @@ children: - /use-copilot-agents - /use-ai-models - /provide-context - - /configure-custom-instructions + - /configure-custom-instructions-in-your-ide - /configure-content-exclusion - /use-copilot-for-common-tasks - /configure-personal-settings diff --git a/content/copilot/how-tos/provide-context/use-copilot-spaces/index.md b/content/copilot/how-tos/provide-context/use-copilot-spaces/index.md index 80315fc609d3..0728c87e4323 100644 --- a/content/copilot/how-tos/provide-context/use-copilot-spaces/index.md +++ b/content/copilot/how-tos/provide-context/use-copilot-spaces/index.md @@ -5,9 +5,7 @@ intro: "Organize and centralize relevant content into {% data variables.copilot. versions: feature: copilot children: - - /create-copilot-spaces - /use-copilot-spaces - - /collaborate-with-others redirect_from: - /copilot/using-github-copilot/copilot-spaces - /copilot/how-tos/context/copilot-spaces diff --git a/content/copilot/how-tos/provide-context/use-copilot-spaces/use-copilot-spaces.md b/content/copilot/how-tos/provide-context/use-copilot-spaces/use-copilot-spaces.md index c314e78dfb9d..676de7eebbc7 100644 --- a/content/copilot/how-tos/provide-context/use-copilot-spaces/use-copilot-spaces.md +++ b/content/copilot/how-tos/provide-context/use-copilot-spaces/use-copilot-spaces.md @@ -12,14 +12,6 @@ category: For information on creating {% data variables.copilot.copilot_spaces %}, see [AUTOTITLE](/copilot/how-tos/provide-context/use-copilot-spaces/create-copilot-spaces). -## Using {% data variables.copilot.copilot_spaces %} in {% data variables.product.github %} - -Once you've added context to your space, you can ask {% data variables.product.prodname_copilot_short %} questions in the space's chat interface in {% data variables.product.github %}. Your chat will be grounded in the context you've added. You can view all conversations you have had in the space's "Conversations" tab. - -You can also change the large language model (LLM) used for your space by selecting the **CURRENT-MODEL** {% octicon "chevron-down" aria-hidden="true" aria-label="chevron-down" %} dropdown menu, then clicking the AI model of your choice. For more information, see [AUTOTITLE](/copilot/reference/ai-models/model-comparison). - -To star your favorite spaces so that you can easily find them later, you can click **{% octicon "star" aria-hidden="true" aria-label="star" %}** in the top right corner of the space. To view all spaces available to you, including starred spaces, go to [https://github.com/copilot/spaces](https://github.com/copilot/spaces?ref_product=copilot&ref_type=engagement&ref_style=text). - ## Using {% data variables.copilot.copilot_spaces %} in your IDE You can also access the information and context from {% data variables.copilot.copilot_spaces_short %} directly in your IDE using the {% data variables.product.github %} MCP server. This allows you to leverage your curated context while coding without switching between your IDE and the web interface. diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/create-custom-agents.md b/content/copilot/how-tos/use-copilot-agents/cloud-agent/create-custom-agents-in-your-ide.md similarity index 56% rename from content/copilot/how-tos/use-copilot-agents/cloud-agent/create-custom-agents.md rename to content/copilot/how-tos/use-copilot-agents/cloud-agent/create-custom-agents-in-your-ide.md index ced4a9130f51..3414cc2224fa 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/create-custom-agents.md +++ b/content/copilot/how-tos/use-copilot-agents/cloud-agent/create-custom-agents-in-your-ide.md @@ -1,6 +1,6 @@ --- -title: Creating custom agents for {% data variables.copilot.copilot_cloud_agent %} -shortTitle: Create custom agents +title: Creating custom agents for {% data variables.copilot.copilot_cloud_agent %} in your IDE +shortTitle: Create custom agents in your IDE intro: You can create specialized agents with tailored expertise for specific development tasks. product: '{% data reusables.gated-features.copilot-cloud-agent %}
Sign up for {% data variables.product.prodname_copilot_short %} {% octicon "link-external" height:16 %}' versions: @@ -9,30 +9,12 @@ category: - Configure Copilot - Author and optimize with Copilot contentType: how-tos -redirect_from: - - /copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents --- {% data variables.copilot.custom_agents_caps_short %} allow you to tailor {% data variables.product.prodname_copilot_short %}'s expertise for specific tasks. For a conceptual overview of {% data variables.copilot.custom_agents_short %}, see [AUTOTITLE](/copilot/concepts/agents/cloud-agent/about-custom-agents). {% data reusables.copilot.custom-agents-ide-preview %} -## Creating a {% data variables.copilot.copilot_custom_agent_short %} profile in a repository on {% data variables.product.github %} - -1. Navigate to the agents tab at [https://github.com/copilot/agents](https://github.com/copilot/agents?ref_product=copilot&ref_type=engagement&ref_style=text). - -1. Using the dropdown menu in the prompt box, select the repository you want to create the {% data variables.copilot.copilot_custom_agent_short %} profile in. - - > [!NOTE] - > Organization and enterprise owners can create organization and enterprise-level {% data variables.copilot.custom_agents_short %} in a `.github-private` repository that are available across all repositories within their organization or enterprise. For more information, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/prepare-for-custom-agents) and [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-organization/prepare-for-custom-agents). - -1. Optionally, select the branch you want to create the {% data variables.copilot.agent_profile %} in. The default is the main branch. -1. Click {% octicon "copilot" aria-label="Select a custom agent" %}, then click **{% octicon "plus" aria-label="Plus button" %} Create an agent**. This will open a template agent profile called `my-agent.agent.md` in the `.github/agents` directory of your target repository. -1. If you are creating an organization or enterprise-level {% data variables.copilot.copilot_custom_agent_short %}, delete the `.github/` portion of the file path to move your template to the root `agents` directory. -1. Edit the filename (the text before `.agent.md`), selecting a unique, descriptive name that identifies the agent's purpose. Note that the filename may only contain the following characters: `.`, `-`, `_`, `a-z`, `A-Z`, `0-9`. -1. Configure the {% data variables.copilot.agent_profile %}, including the name, description, tools, and prompts. For more information on what the {% data variables.copilot.agent_profile %} can include, see [Configuring an {% data variables.copilot.agent_profile %}](#configuring-an-agent-profile). -1. Commit the file to the repository and merge it into the default branch. Go back to the agents tab and refresh the page if needed. Your {% data variables.copilot.copilot_custom_agent_short %} will now appear in the dropdown when you click {% octicon "copilot" aria-hidden="true" aria-label="copilot" %} in the prompt box. - ## Creating a {% data variables.copilot.copilot_custom_agent_short %} profile in {% data variables.product.prodname_vscode %} 1. Open {% data variables.copilot.copilot_chat %} in {% data variables.product.prodname_vscode %}. @@ -81,19 +63,7 @@ To update an {% data variables.copilot.agent_profile %}, from the agents dropdow ## Configuring an {% data variables.copilot.agent_profile %} -An {% data variables.copilot.agent_profile %} is a Markdown file with YAML frontmatter that specifies the {% data variables.copilot.copilot_custom_agent_short %}'s name, description, available tools, and MCP server configurations. Configuring an {% data variables.copilot.agent_profile %} involves defining the agent's identity, capabilities, tool access, and behavioral instructions. - -For detailed configuration information about YAML properties, tools, MCP server setup, tool aliases, and how {% data variables.copilot.custom_agents_short %} are processed, see [AUTOTITLE](/copilot/reference/custom-agents-configuration). - -To configure your {% data variables.copilot.agent_profile %}: - -1. Optionally, write a `name` for your {% data variables.copilot.copilot_custom_agent_short %}. If unset, the name will default to the filename (without the `.md` or `.agent.md` suffix). -1. Write a brief `description` (required) explaining what your agent does and its specific capabilities or domain expertise. -1. In the `tools` property, define which tools the agent can use. This is a list of tool names or aliases, including tools from MCP servers configured in the repository settings or the {% data variables.copilot.agent_profile %} (for example, `tools: ["read", "edit", "search", "some-mcp-server/tool-1"]`). If you omit this property, the agent will have access to all available tools. See "Tools" in [AUTOTITLE](/copilot/reference/custom-agents-configuration#tools). -1. Optionally, in the `mcp-servers` property, you can configure MCP servers that will be available only to this agent to extend its capabilities. See "MCP server configuration details" in [AUTOTITLE](/copilot/reference/custom-agents-configuration#mcp-server-configuration-details). -1. If you are creating and using the {% data variables.copilot.agent_profile %} in {% data variables.product.prodname_vscode_shortname %}, JetBrains IDEs, Eclipse, or Xcode, you can also use the `model` property to control which AI model the agent should use. -1. Optionally, set the `target` property to either `vscode` or `github-copilot` if you want to only use the agent in a specific environment. The agent will be available in both environments if you omit the property. -1. Write the agent's prompt. Define the agent's behavior, expertise, and instructions in the Markdown content below the YAML frontmatter. The prompt can be a maximum of 30,000 characters. +{% data reusables.copilot.custom-agents-configuring-profile %} ## Example {% data variables.copilot.agent_profiles %} @@ -101,15 +71,7 @@ To configure your {% data variables.copilot.agent_profile %}: ## Using {% data variables.copilot.custom_agents_short %} -Once you've created a {% data variables.copilot.copilot_custom_agent_short %}, you can use it wherever {% data variables.copilot.copilot_cloud_agent %} is available. - -* When prompting {% data variables.copilot.copilot_cloud_agent %} with a task on {% data variables.product.prodname_dotcom_the_website %}, use the dropdown menu in the agents panel or agents tab to select your {% data variables.copilot.copilot_custom_agent_short %} instead of the default {% data variables.copilot.copilot_cloud_agent_short %}. -* When assigning {% data variables.copilot.copilot_cloud_agent %} to an issue, you can select your {% data variables.copilot.copilot_custom_agent_short %} from the dropdown menu to handle the issue with your specialized configuration. -* When using the {% data variables.copilot.copilot_cli %}, you can choose to use a particular {% data variables.copilot.copilot_custom_agent_short %} by using the `/agent` slash command or referencing the agent in a prompt or via a command-line argument. For more information, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/use-copilot-cli#use-custom-agents). - -When {% data variables.product.prodname_copilot_short %} opens pull requests, it will note which {% data variables.copilot.copilot_custom_agent_short %} was used to complete the work in the pull request description. - -For more information on using {% data variables.copilot.copilot_cloud_agent %}, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/create-a-pr). +{% data reusables.copilot.custom-agents-using %} ### Using {% data variables.copilot.custom_agents_short %} in your IDE @@ -121,6 +83,4 @@ For more information on {% data variables.copilot.custom_agents_short %} in {% d ## Next steps -* For a hands-on tutorial to create your first {% data variables.copilot.copilot_custom_agent_short %}, see [AUTOTITLE](/copilot/tutorials/customization-library/custom-agents/your-first-custom-agent). -* For detailed configuration information, see [AUTOTITLE](/copilot/reference/custom-agents-configuration). -* For information on using cloud agents, including your {% data variables.copilot.custom_agents_short %}, to create pull requests, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/create-a-pr). +{% data reusables.copilot.custom-agents-next-steps %} diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/index.md b/content/copilot/how-tos/use-copilot-agents/cloud-agent/index.md index ccc6aeadc5c2..02ba41d9de7b 100644 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/index.md +++ b/content/copilot/how-tos/use-copilot-agents/cloud-agent/index.md @@ -8,10 +8,6 @@ versions: children: - /create-a-pr - /track-copilot-sessions - - /create-custom-agents - - /test-custom-agents - - /add-skills - - /extend-cloud-agent-with-mcp - /integrate-cloud-agent-with-jira - /integrate-cloud-agent-with-slack - /integrate-cloud-agent-with-teams @@ -19,9 +15,7 @@ children: - /integrate-cloud-agent-with-azure-boards - /changing-the-ai-model - /configuring-agent-settings - - /customize-the-agent-environment - - /customize-the-agent-firewall - - /use-hooks + - /create-custom-agents-in-your-ide - /troubleshoot-cloud-agent redirect_from: - /copilot/how-tos/use-copilot-agents/coding-agent diff --git a/content/copilot/how-tos/use-copilot-agents/cloud-agent/use-hooks.md b/content/copilot/how-tos/use-copilot-agents/cloud-agent/use-hooks.md deleted file mode 100644 index aa8e897d9c6b..000000000000 --- a/content/copilot/how-tos/use-copilot-agents/cloud-agent/use-hooks.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Using hooks with GitHub Copilot agents -shortTitle: Use hooks -intro: 'Extend and customize {% data variables.product.prodname_copilot %} agent behavior by executing custom shell commands at key points during agent execution.' -versions: - feature: copilot -contentType: how-tos -category: - - Configure Copilot -redirect_from: - - /copilot/how-tos/use-copilot-agents/coding-agent/use-hooks ---- - -{% data reusables.copilot.cloud-agent.hooks-intro %} - -## Creating a hook in a repository on {% data variables.product.github %} - -{% data reusables.copilot.cloud-agent.create-hooks-instructions %} - -## Troubleshooting - -{% data reusables.copilot.cloud-agent.troubleshoot-hooks %} - -## Further reading - -* For more information about configuring hooks, see [AUTOTITLE](/copilot/reference/hooks-configuration) -* For more information about {% data variables.copilot.copilot_cloud_agent %}, see [AUTOTITLE](/copilot/concepts/agents/cloud-agent/about-cloud-agent) -* For more information about {% data variables.copilot.copilot_cli %}, see [AUTOTITLE](/copilot/concepts/agents/about-copilot-cli) -* For information about customizing the agent environment, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/customize-the-agent-environment) diff --git a/content/copilot/reference/copilot-billing/license-changes.md b/content/copilot/reference/copilot-billing/license-changes.md index 24f7cfcc6eee..894fa397bf74 100644 --- a/content/copilot/reference/copilot-billing/license-changes.md +++ b/content/copilot/reference/copilot-billing/license-changes.md @@ -11,7 +11,7 @@ contentType: reference --- > [!IMPORTANT] -> **Starting April 20, 2026**, new sign-ups for {% data variables.copilot.copilot_pro_short %}, {% data variables.copilot.copilot_pro_plus_short %}, and student plans are temporarily paused. However, existing {% data variables.product.prodname_copilot_short %} plans can still be upgraded, downgraded, or canceled. If you hit unexpected limits as a result of these changes, you can cancel your Pro or Pro+ subscription and you will not be charged for April usage. Please reach out to [GitHub support](https://support.github.com/) between April 20 and May 20, 2026, for a refund. +> **Starting April 20, 2026**, new sign-ups for {% data variables.copilot.copilot_pro_short %}, {% data variables.copilot.copilot_pro_plus_short %}, and student plans are temporarily paused. However, existing {% data variables.product.prodname_copilot_short %} plans can still be upgraded, downgraded, or canceled. If you hit unexpected limits as a result of these changes, you can cancel your Pro or Pro+ subscription and receive a refund for the time remaining on your current subscription. Please reach out to [GitHub support](https://support.github.com/) between April 20 and May 20, 2026, for a refund. {% data variables.product.prodname_copilot_short %} follows the same billing rules as other license-based products on {% data variables.product.company_short %}. For the general concepts, see: diff --git a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md index e5d7181108e3..4a1dd20b8dac 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md @@ -138,7 +138,7 @@ COPILOT_GITHUB_TOKEN=github_pat_... copilot | `/model`, `/models [MODEL]` | Select the AI model you want to use. | | `/plan [PROMPT]` | Create an implementation plan before coding. | | `/plugin [marketplace\|install\|uninstall\|update\|list] [ARGS...]` | Manage plugins and plugin marketplaces. See [AUTOTITLE](/copilot/concepts/agents/copilot-cli/about-cli-plugins). | -| `/pr [view\|create\|fix\|auto]` | Operate on pull requests for the current branch. | +| `/pr [view\|create\|fix\|auto]` | Manage pull requests for the current branch. See [AUTOTITLE](/copilot/how-tos/copilot-cli/manage-pull-requests). | | `/remote` | Enable remote access to this session from {% data variables.product.prodname_dotcom_the_website %} and {% data variables.product.prodname_mobile %}. See [AUTOTITLE](/copilot/how-tos/copilot-cli/steer-remotely). | | `/rename [NAME]` | Rename the current session (auto-generates a name if omitted; alias for `/session rename`). | | `/research TOPIC` | Run a deep research investigation using {% data variables.product.github %} search and web sources. See [AUTOTITLE](/copilot/concepts/agents/copilot-cli/research). | diff --git a/data/release-notes/enterprise-server/3-14/26.yml b/data/release-notes/enterprise-server/3-14/26.yml new file mode 100644 index 000000000000..6f32b61ac5cd --- /dev/null +++ b/data/release-notes/enterprise-server/3-14/26.yml @@ -0,0 +1,67 @@ +date: '2026-04-21' +sections: + security_fixes: + - | + **HIGH**: An attacker could gain unauthorized access to private repositories by abusing scoped user-to-server (`ghu_`) tokens after their associated GitHub App installation was revoked or deleted. In certain cases, the authorization layer could incorrectly fall back to a global installation context instead of rejecting the request, allowing the token to access resources outside its intended installation or repository scope. This issue could be chained with weaknesses in token revocation timing and SSH push attribution to obtain a victim-scoped token and read private repository contents without victim interaction. GitHub has requested CVE ID [CVE-2026-5845](https://www.cve.org/cverecord?id=CVE-2026-5845) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker could extract sensitive environment variables from a GitHub Enterprise Server instance through a timing side-channel attack against the notebook rendering service. When private mode was disabled, the notebook viewer followed HTTP redirects without revalidating the destination host, enabling an unauthenticated Server-Side Request Forgery (SSRF) to internal services. By measuring response time differences, an attacker could infer secret values character by character. GitHub has requested CVE ID [CVE-2026-5921](https://www.cve.org/cverecord?id=CVE-2026-5921) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **HIGH**: A Management Console administrator could inject shell metacharacters into configuration fields via the Management Console configuration API, leading to arbitrary command execution on the appliance as the admin OS user. GitHub has requested CVE ID [CVE-2026-4821](https://www.cve.org/cverecord?id=CVE-2026-4821) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker with knowledge of a target application's registered OAuth callback URL could gain unauthorized access to user accounts by exploiting incorrect regular expression matching in callback URL validation. GitHub has requested CVE ID [CVE-2026-4296](https://www.cve.org/cverecord?id=CVE-2026-4296) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An attacker with permission to manage secret scanning push protection settings in one repository could add or remove delegated bypass reviewers in a different repository by exploiting an incorrect authorization check in the `/settings/security_analysis/bypass_reviewers` endpoints. Authorization was checked against the repository in the URL route, but the action was applied to a different repository specified in the request body. The impact is limited to assigning existing trusted users as bypass reviewers. GitHub has requested CVE ID [CVE-2026-3307](https://www.cve.org/cverecord?id=CVE-2026-3307) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An authenticated attacker could determine the names of private repositories by their numeric ID through the mobile upload policy API endpoint, which returned repository names in validation error messages without verifying the caller's access. GitHub has requested [CVE ID CVE-2026-5512](https://www.cve.org/cverecord?id=CVE-2026-5512) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + On an instance with GitHub Actions enabled, diagnostic log files for storage connectivity checks did not persist to disk when site administrators clicked **Test storage settings** in the Management Console or ran `ghe-config-apply` to apply configuration changes. This made storage connection failures difficult to troubleshoot because logs were unavailable in support bundles. + - | + When Consul replication failed to start, a misleading error message `exit: check_consul_replication: numeric argument required` was emitted to `ghe-config.log`. + - | + Consul replication would sometimes fail to start and would repeatedly display an error message `WARNING: Consul KV Replication Error` before terminating. + - | + On instances with Dependabot enabled, hotpatch upgrades could lock the Nomad jobs queue. + - | + The site admin bar displayed debugging information used by GitHub. + - | + On an instance with busy databases, online schema migrations using gh-ost failed because the cut-over lock timeout defaulted to 3 seconds, which was insufficient to acquire an exclusive table lock under continuous traffic. + known_issues: + - | + First time setups of GitHub Actions with OpenID Connect (OIDC) fail with an error on the `Update Servicing Resources` step. This problem does not affect instances where GitHub Actions is already enabled. + + As a workaround, you can enable Actions without OIDC, then enable OIDC **immediately** once the process completes. You should do this immediately because enabling OIDC will remove all access to existing Actions logs and artifacts. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [Troubleshooting access to the Management Console](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + On an instance with the HTTP `X-Forwarded-For` header configured for use behind a load balancer, all client IP addresses in the instance's audit log erroneously appear as 127.0.0.1. + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may timeout on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shutdown the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + An organization-level code scanning configuration page is displayed on instances that do not use GitHub Advanced Security or code scanning. + - | + In the header bar displayed to site administrators, some icons are not available. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + Unexpected elements may appear in the UI on the repo overview page for locked repositories. + - | + GitHub Enterprise Server releases shipped with mismatched Git versions between containers. diff --git a/data/release-notes/enterprise-server/3-15/21.yml b/data/release-notes/enterprise-server/3-15/21.yml new file mode 100644 index 000000000000..82969c569f71 --- /dev/null +++ b/data/release-notes/enterprise-server/3-15/21.yml @@ -0,0 +1,82 @@ +date: '2026-04-21' +sections: + security_fixes: + - | + **HIGH**: An attacker could gain unauthorized access to private repositories by abusing scoped user-to-server (`ghu_`) tokens after their associated GitHub App installation was revoked or deleted. In certain cases, the authorization layer could incorrectly fall back to a global installation context instead of rejecting the request, allowing the token to access resources outside its intended installation or repository scope. This issue could be chained with weaknesses in token revocation timing and SSH push attribution to obtain a victim-scoped token and read private repository contents without victim interaction. GitHub has requested CVE ID [CVE-2026-5845](https://www.cve.org/cverecord?id=CVE-2026-5845) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker could extract sensitive environment variables from a GitHub Enterprise Server instance through a timing side-channel attack against the notebook rendering service. When private mode was disabled, the notebook viewer followed HTTP redirects without revalidating the destination host, enabling an unauthenticated Server-Side Request Forgery (SSRF) to internal services. By measuring response time differences, an attacker could infer secret values character by character. GitHub has requested CVE ID [CVE-2026-5921](https://www.cve.org/cverecord?id=CVE-2026-5921) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **HIGH**: A Management Console administrator could inject shell metacharacters into configuration fields via the Management Console configuration API, leading to arbitrary command execution on the appliance as the admin OS user. GitHub has requested CVE ID [CVE-2026-4821](https://www.cve.org/cverecord?id=CVE-2026-4821) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker with knowledge of a target application's registered OAuth callback URL could gain unauthorized access to user accounts by exploiting incorrect regular expression matching in callback URL validation. GitHub has requested CVE ID [CVE-2026-4296](https://www.cve.org/cverecord?id=CVE-2026-4296) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An attacker with permission to manage secret scanning push protection settings in one repository could add or remove delegated bypass reviewers in a different repository by exploiting an incorrect authorization check in the `/settings/security_analysis/bypass_reviewers` endpoints. Authorization was checked against the repository in the URL route, but the action was applied to a different repository specified in the request body. The impact is limited to assigning existing trusted users as bypass reviewers. GitHub has requested CVE ID [CVE-2026-3307](https://www.cve.org/cverecord?id=CVE-2026-3307) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An authenticated attacker could determine the names of private repositories by their numeric ID through the mobile upload policy API endpoint, which returned repository names in validation error messages without verifying the caller's access. GitHub has requested [CVE ID CVE-2026-5512](https://www.cve.org/cverecord?id=CVE-2026-5512) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **LOW**: GitHub Enterprise Server included React versions 19.0, 19.1, and 19.2 in its package, which contain vulnerabilities in the React Server Components protocol (CVE-2025-55182, CVE-2025-66478). GitHub Enterprise Server does not use React Server Components and was not vulnerable to exploitation. React has been updated to version 19.2.3 to address findings from security scanning tools. + bugs: + - | + On an instance with GitHub Actions enabled, diagnostic log files for storage connectivity checks did not persist to disk when site administrators clicked **Test storage settings** in the Management Console or ran `ghe-config-apply` to apply configuration changes. This made storage connection failures difficult to troubleshoot because logs were unavailable in support bundles. + - | + When Consul replication failed to start, a misleading error message `exit: check_consul_replication: numeric argument required` was emitted to `ghe-config.log`. + - | + Consul replication would sometimes fail to start and would repeatedly display an error message `WARNING: Consul KV Replication Error` before terminating. + - | + On instances with Dependabot enabled, hotpatch upgrades could lock the Nomad jobs queue. + - | + On instances connected to GitHub Enterprise Cloud with data residency, the "GitHub.com actions" setting appeared in the GitHub Connect configuration despite this feature not being available for data residency deployments. + - | + The site admin bar displayed debugging information used by GitHub. + - | + Suspended users were listed in an organization's list of members. + - | + On an instance with busy databases, online schema migrations using gh-ost failed because the cut-over lock timeout defaulted to 3 seconds, which was insufficient to acquire an exclusive table lock under continuous traffic. + changes: + - | + Administrators can now set `mysql.innodb-online-alter-log-max-size` with `ghe-config` so the value persists when a configuration is applied or upgraded. + known_issues: + - | + First time setups of GitHub Actions with OpenID Connect (OIDC) fail with an error on the `Update Servicing Resources` step. This problem does not affect instances where GitHub Actions is already enabled. + + As a workaround, you can enable Actions without OIDC, then enable OIDC **immediately** once the process completes. You should do this immediately because enabling OIDC will remove all access to existing Actions logs and artifacts. + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [Troubleshooting access to the Management Console](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + On an instance with the HTTP `X-Forwarded-For` header configured for use behind a load balancer, all client IP addresses in the instance's audit log erroneously appear as 127.0.0.1. + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may timeout on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shutdown the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + An organization-level code scanning configuration page is displayed on instances that do not use GitHub Advanced Security or code scanning. + - | + In the header bar displayed to site administrators, some icons are not available. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + Admins setting up cluster high availability (HA) may encounter a spokes error when running `ghe-cluster-repl-status` if a new organization and repositories are created before using the `ghe-cluster-repl-bootstrap` command. To avoid this issue, complete the cluster HA setup with `ghe-cluster-repl-bootstrap` before creating new organizations and repositories. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + Unexpected elements may appear in the UI on the repo overview page for locked repositories. + - | + GitHub Enterprise Server releases shipped with mismatched Git versions between containers. diff --git a/data/release-notes/enterprise-server/3-16/17.yml b/data/release-notes/enterprise-server/3-16/17.yml new file mode 100644 index 000000000000..bc537772565e --- /dev/null +++ b/data/release-notes/enterprise-server/3-16/17.yml @@ -0,0 +1,94 @@ +date: '2026-04-21' +sections: + security_fixes: + - | + **HIGH**: An attacker could gain unauthorized access to private repositories by abusing scoped user-to-server (`ghu_`) tokens after their associated GitHub App installation was revoked or deleted. In certain cases, the authorization layer could incorrectly fall back to a global installation context instead of rejecting the request, allowing the token to access resources outside its intended installation or repository scope. This issue could be chained with weaknesses in token revocation timing and SSH push attribution to obtain a victim-scoped token and read private repository contents without victim interaction. GitHub has requested CVE ID [CVE-2026-5845](https://www.cve.org/cverecord?id=CVE-2026-5845) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker could extract sensitive environment variables from a GitHub Enterprise Server instance through a timing side-channel attack against the notebook rendering service. When private mode was disabled, the notebook viewer followed HTTP redirects without revalidating the destination host, enabling an unauthenticated Server-Side Request Forgery (SSRF) to internal services. By measuring response time differences, an attacker could infer secret values character by character. GitHub has requested CVE ID [CVE-2026-5921](https://www.cve.org/cverecord?id=CVE-2026-5921) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **HIGH**: A Management Console administrator could inject shell metacharacters into configuration fields via the Management Console configuration API, leading to arbitrary command execution on the appliance as the admin OS user. GitHub has requested CVE ID [CVE-2026-4821](https://www.cve.org/cverecord?id=CVE-2026-4821) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker with knowledge of a target application's registered OAuth callback URL could gain unauthorized access to user accounts by exploiting incorrect regular expression matching in callback URL validation. GitHub has requested CVE ID [CVE-2026-4296](https://www.cve.org/cverecord?id=CVE-2026-4296) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An attacker with permission to manage secret scanning push protection settings in one repository could add or remove delegated bypass reviewers in a different repository by exploiting an incorrect authorization check in the `/settings/security_analysis/bypass_reviewers` endpoints. Authorization was checked against the repository in the URL route, but the action was applied to a different repository specified in the request body. The impact is limited to assigning existing trusted users as bypass reviewers. GitHub has requested CVE ID [CVE-2026-3307](https://www.cve.org/cverecord?id=CVE-2026-3307) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An authenticated attacker could determine the names of private repositories by their numeric ID through the mobile upload policy API endpoint, which returned repository names in validation error messages without verifying the caller's access. GitHub has requested [CVE ID CVE-2026-5512](https://www.cve.org/cverecord?id=CVE-2026-5512) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **LOW**: GitHub Enterprise Server included React versions 19.0, 19.1, and 19.2 in its package, which contain vulnerabilities in the React Server Components protocol (CVE-2025-55182, CVE-2025-66478). GitHub Enterprise Server does not use React Server Components and was not vulnerable to exploitation. React has been updated to version 19.2.3 to address findings from security scanning tools. + bugs: + - | + Dependabot security update jobs failed silently when dependency groups with `applies-to: security-updates` were configured. + - | + On an instance with GitHub Actions enabled, diagnostic log files for storage connectivity checks did not persist to disk when site administrators clicked **Test storage settings** in the Management Console or ran `ghe-config-apply` to apply configuration changes. This made storage connection failures difficult to troubleshoot because logs were unavailable in support bundles. + - | + During initial setup of a new instance, site administrators saw an "Oops! A configuration run is already in progress" error message in the Management Console even though `ghe-config-apply` had not been run. + - | + When Consul replication failed to start, a misleading error message `exit: check_consul_replication: numeric argument required` was emitted to `ghe-config.log`. + - | + Consul replication would sometimes fail to start and would repeatedly display an error message `WARNING: Consul KV Replication Error` before terminating. + - | + On instances with Dependabot enabled, hotpatch upgrades could lock the Nomad jobs queue. + - | + On instances connected to GitHub Enterprise Cloud with data residency, the "GitHub.com actions" setting appeared in the GitHub Connect configuration despite this feature not being available for data residency deployments. + - | + On instances with GitHub Actions enabled, errors appeared in logs related to missing Elasticsearch field mappings for workflow runs. The workflow run data included an `archived` field that was not defined in the Elasticsearch index mapping. + - | + The site admin bar displayed debugging information used by GitHub. + - | + Suspended users were listed in an organization's list of members. + - | + On an instance with busy databases, online schema migrations using gh-ost failed because the cut-over lock timeout defaulted to 3 seconds, which was insufficient to acquire an exclusive table lock under continuous traffic. + changes: + - | + Administrators can now set `mysql.innodb-online-alter-log-max-size` with `ghe-config` so the value persists when a configuration is applied or upgraded. + known_issues: + - | + First time setups of GitHub Actions with OpenID Connect (OIDC) fail with an error on the `Update Servicing Resources` step. This problem does not affect instances where GitHub Actions is already enabled. + + As a workaround, you can enable Actions without OIDC, then enable OIDC **immediately** once the process completes. You should do this immediately because enabling OIDC will remove all access to existing Actions logs and artifacts. + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [Troubleshooting access to the Management Console](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + On an instance with the HTTP `X-Forwarded-For` header configured for use behind a load balancer, all client IP addresses in the instance's audit log erroneously appear as 127.0.0.1. + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may timeout on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shutdown the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + An organization-level code scanning configuration page is displayed on instances that do not use GitHub Advanced Security or code scanning. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + Admins setting up cluster high availability (HA) may encounter a spokes error when running `ghe-cluster-repl-status` if a new organization and repositories are created before using the `ghe-cluster-repl-bootstrap` command. To avoid this issue, complete the cluster HA setup with `ghe-cluster-repl-bootstrap` before creating new organizations and repositories. + - | + In a cluster, the host running restore requires access the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + Unexpected elements may appear in the UI on the repo overview page for locked repositories. + - | + Audit log entries for pre-receive hooks that have been rejected may not be recorded. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. + - | + GitHub Enterprise Server releases shipped with mismatched Git versions between containers. diff --git a/data/release-notes/enterprise-server/3-17/14.yml b/data/release-notes/enterprise-server/3-17/14.yml new file mode 100644 index 000000000000..98912b0fdc10 --- /dev/null +++ b/data/release-notes/enterprise-server/3-17/14.yml @@ -0,0 +1,112 @@ +date: '2026-04-21' +sections: + security_fixes: + - | + **HIGH**: An attacker could gain unauthorized access to private repositories by abusing scoped user-to-server (`ghu_`) tokens after their associated GitHub App installation was revoked or deleted. In certain cases, the authorization layer could incorrectly fall back to a global installation context instead of rejecting the request, allowing the token to access resources outside its intended installation or repository scope. This issue could be chained with weaknesses in token revocation timing and SSH push attribution to obtain a victim-scoped token and read private repository contents without victim interaction. GitHub has requested CVE ID [CVE-2026-5845](https://www.cve.org/cverecord?id=CVE-2026-5845) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker could extract sensitive environment variables from a GitHub Enterprise Server instance through a timing side-channel attack against the notebook rendering service. When private mode was disabled, the notebook viewer followed HTTP redirects without revalidating the destination host, enabling an unauthenticated Server-Side Request Forgery (SSRF) to internal services. By measuring response time differences, an attacker could infer secret values character by character. GitHub has requested CVE ID [CVE-2026-5921](https://www.cve.org/cverecord?id=CVE-2026-5921) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **HIGH**: A Management Console administrator could inject shell metacharacters into configuration fields via the Management Console configuration API, leading to arbitrary command execution on the appliance as the admin OS user. GitHub has requested CVE ID [CVE-2026-4821](https://www.cve.org/cverecord?id=CVE-2026-4821) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker with knowledge of a target application's registered OAuth callback URL could gain unauthorized access to user accounts by exploiting incorrect regular expression matching in callback URL validation. GitHub has requested CVE ID [CVE-2026-4296](https://www.cve.org/cverecord?id=CVE-2026-4296) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An attacker with permission to manage secret scanning push protection settings in one repository could add or remove delegated bypass reviewers in a different repository by exploiting an incorrect authorization check in the `/settings/security_analysis/bypass_reviewers` endpoints. Authorization was checked against the repository in the URL route, but the action was applied to a different repository specified in the request body. The impact is limited to assigning existing trusted users as bypass reviewers. GitHub has requested CVE ID [CVE-2026-3307](https://www.cve.org/cverecord?id=CVE-2026-3307) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An authenticated attacker could determine the names of private repositories by their numeric ID through the mobile upload policy API endpoint, which returned repository names in validation error messages without verifying the caller's access. GitHub has requested [CVE ID CVE-2026-5512](https://www.cve.org/cverecord?id=CVE-2026-5512) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **LOW**: GitHub Enterprise Server included React versions 19.0, 19.1, and 19.2 in its package, which contain vulnerabilities in the React Server Components protocol (CVE-2025-55182, CVE-2025-66478). GitHub Enterprise Server does not use React Server Components and was not vulnerable to exploitation. React has been updated to version 19.2.3 to address findings from security scanning tools. + bugs: + - | + Dependabot security update jobs failed silently when dependency groups with `applies-to: security-updates` were configured. + - | + After administrators installed or removed a custom certificate authority (CA) certificate with `ghe-ssl-ca-certificate-install`, Dependabot services continued using the previous CA store and could fail to connect to external registries that required the updated CA. + - | + On an instance with GitHub Actions enabled, diagnostic log files for storage connectivity checks did not persist to disk when site administrators clicked **Test storage settings** in the Management Console or ran `ghe-config-apply` to apply configuration changes. This made storage connection failures difficult to troubleshoot because logs were unavailable in support bundles. + - | + During initial setup of a new instance, site administrators saw an "Oops! A configuration run is already in progress" error message in the Management Console even though `ghe-config-apply` had not been run. + - | + When Consul replication failed to start, a misleading error message `exit: check_consul_replication: numeric argument required` was emitted to `ghe-config.log`. + - | + Consul replication would sometimes fail to start and would repeatedly display an error message `WARNING: Consul KV Replication Error` before terminating. + - | + On instances with Dependabot enabled, hotpatch upgrades could lock the Nomad jobs queue. + - | + On instances with GitHub Actions enabled, workflows using `actions/github-script@v7` failed with an Internal Server Error during action resolution. In the previous GHES version, the bundled actions/github-script repository referenced a Git object that no longer existed, causing all workflows using `actions/github-script@v7` to fail. + - | + API consumers could not access secret scanning scan history for archived repositories, even when the organization had a GitHub Advanced Security license. + - | + When applying a hotpatch or running a configuration with `ghe-config-apply`, the configuration run could fail with `ERROR: Restoring CodeQL Action release tags` if internal Git services were not yet fully available. The error message `SpokesAPI::TwirpServerError: unavailable` appeared in logs. + - | + On instances connected to GitHub Enterprise Cloud with data residency, the "GitHub.com actions" setting appeared in the GitHub Connect configuration despite this feature not being available for data residency deployments. + - | + On instances with GitHub Actions enabled, errors appeared in logs related to missing Elasticsearch field mappings for workflow runs. The workflow run data included an `archived` field that was not defined in the Elasticsearch index mapping. + - | + The site admin bar displayed debugging information used by GitHub. + - | + Suspended users were listed in an organization's list of members. + - | + Migrations to GitHub Enterprise Server failed when the importer service tried to import a pull request review comment that referenced a garbage-collected commit. Now, these comments are skipped gracefully. + - | + The site admin "All organizations" report included soft-deleted organizations. + - | + Users with GitHub Advanced Security enabled received a 503 error when retrieving code scanning alerts via the API or in the UI due to inefficient database query execution. + - | + On an instance with busy databases, online schema migrations using gh-ost failed because the cut-over lock timeout defaulted to 3 seconds, which was insufficient to acquire an exclusive table lock under continuous traffic. + changes: + - | + Administrators can now set `mysql.innodb-online-alter-log-max-size` with `ghe-config` so the value persists when a configuration is applied or upgraded. + - | + Administrators can configure the maximum number of concurrent HTTP/2 streams per connection for HAProxy. To set this value, use `ghe-config core.haproxy-h2-max-concurrent-streams VALUE` and run `ghe-config-apply`. Previously, this value was hardcoded to 100. + - | + To limit misleading error messages when the `mysql_exporter` and `sql_exporter` exporters try to connect to the database, both exporters use an IPv4 address. + known_issues: + - | + First time setups of GitHub Actions with OpenID Connect (OIDC) fail with an error on the `Update Servicing Resources` step. This problem does not affect instances where GitHub Actions is already enabled. + + As a workaround, you can enable Actions without OIDC, then enable OIDC **immediately** once the process completes. You should do this immediately because enabling OIDC will remove all access to existing Actions logs and artifacts. + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [Troubleshooting access to the Management Console](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + On an instance with the HTTP `X-Forwarded-For` header configured for use behind a load balancer, all client IP addresses in the instance's audit log erroneously appear as 127.0.0.1. + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may timeout on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shutdown the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + An organization-level code scanning configuration page is displayed on instances that do not use GitHub Advanced Security or code scanning. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + Admins setting up cluster high availability (HA) may encounter a spokes error when running `ghe-cluster-repl-status` if a new organization and repositories are created before using the `ghe-cluster-repl-bootstrap` command. To avoid this issue, complete the cluster HA setup with `ghe-cluster-repl-bootstrap` before creating new organizations and repositories. + - | + In a cluster, the host running restore requires access the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + Unexpected elements may appear in the UI on the repo overview page for locked repositories. + - | + When publishing npm packages in a workflow after restoring from a backup to GitHub Enterprise Server 3.13.5.gm4 or 3.14.2.gm3, you may encounter a `401 Unauthorized` error from the GitHub Packages service. This can happen if the restore is from an N-1 or N-2 version and the workflow targets the npm endpoint on the backup instance. To avoid this issue, ensure the access token is valid and includes the correct scopes for publishing to GitHub Packages. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. + - | + GitHub Enterprise Server releases shipped with mismatched Git versions between containers. diff --git a/data/release-notes/enterprise-server/3-18/8.yml b/data/release-notes/enterprise-server/3-18/8.yml new file mode 100644 index 000000000000..089bb149924b --- /dev/null +++ b/data/release-notes/enterprise-server/3-18/8.yml @@ -0,0 +1,125 @@ +date: '2026-04-21' +sections: + security_fixes: + - | + **HIGH**: An attacker could gain unauthorized access to private repositories by abusing scoped user-to-server (`ghu_`) tokens after their associated GitHub App installation was revoked or deleted. In certain cases, the authorization layer could incorrectly fall back to a global installation context instead of rejecting the request, allowing the token to access resources outside its intended installation or repository scope. This issue could be chained with weaknesses in token revocation timing and SSH push attribution to obtain a victim-scoped token and read private repository contents without victim interaction. GitHub has requested CVE ID [CVE-2026-5845](https://www.cve.org/cverecord?id=CVE-2026-5845) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker could extract sensitive environment variables from a GitHub Enterprise Server instance through a timing side-channel attack against the notebook rendering service. When private mode was disabled, the notebook viewer followed HTTP redirects without revalidating the destination host, enabling an unauthenticated Server-Side Request Forgery (SSRF) to internal services. By measuring response time differences, an attacker could infer secret values character by character. GitHub has requested CVE ID [CVE-2026-5921](https://www.cve.org/cverecord?id=CVE-2026-5921) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **HIGH**: A Management Console administrator could inject shell metacharacters into configuration fields via the Management Console configuration API, leading to arbitrary command execution on the appliance as the admin OS user. GitHub has requested CVE ID [CVE-2026-4821](https://www.cve.org/cverecord?id=CVE-2026-4821) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker with knowledge of a target application's registered OAuth callback URL could gain unauthorized access to user accounts by exploiting incorrect regular expression matching in callback URL validation. GitHub has requested CVE ID [CVE-2026-4296](https://www.cve.org/cverecord?id=CVE-2026-4296) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An attacker with permission to manage secret scanning push protection settings in one repository could add or remove delegated bypass reviewers in a different repository by exploiting an incorrect authorization check in the `/settings/security_analysis/bypass_reviewers` endpoints. Authorization was checked against the repository in the URL route, but the action was applied to a different repository specified in the request body. The impact is limited to assigning existing trusted users as bypass reviewers. GitHub has requested CVE ID [CVE-2026-3307](https://www.cve.org/cverecord?id=CVE-2026-3307) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An authenticated attacker could determine the names of private repositories by their numeric ID through the mobile upload policy API endpoint, which returned repository names in validation error messages without verifying the caller's access. GitHub has requested [CVE ID CVE-2026-5512](https://www.cve.org/cverecord?id=CVE-2026-5512) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + Dependabot security update jobs failed silently when dependency groups with `applies-to: security-updates` were configured. + - | + After administrators installed or removed a custom certificate authority (CA) certificate with `ghe-ssl-ca-certificate-install`, Dependabot services continued using the previous CA store and could fail to connect to external registries that required the updated CA. + - | + On an instance with GitHub Actions enabled, diagnostic log files for storage connectivity checks did not persist to disk when site administrators clicked **Test storage settings** in the Management Console or ran `ghe-config-apply` to apply configuration changes. This made storage connection failures difficult to troubleshoot because logs were unavailable in support bundles. + - | + During initial setup of a new instance, site administrators saw an "Oops! A configuration run is already in progress" error message in the Management Console even though `ghe-config-apply` had not been run. + - | + On instances using the new OpenTelemetry-based metrics stack, upgrading the instance re-enabled the legacy collectd-based metrics stack. + - | + Cluster administrators experienced `ghe-config-apply` failures when all replica nodes were marked offline and unreachable. Previously, `ghe-cluster-config-update` attempted to sync configuration files to an empty host list, causing the sync step to fail. + - | + Administrators experienced `ghe-support-bundle` appearing to hang on instances configured for high availability when one or more replica nodes were offline or unreachable during connectivity checks. + - | + When Consul replication failed to start, a misleading error message `exit: check_consul_replication: numeric argument required` was emitted to `ghe-config.log`. + - | + Consul replication would sometimes fail to start and would repeatedly display an error message `WARNING: Consul KV Replication Error` before terminating. + - | + On instances with Dependabot enabled, hotpatch upgrades could lock the Nomad jobs queue. + - | + When site administrators set the `observability.otelcol.gogc-enabled` parameter to a boolean value, the `config-apply` failed. + - | + On instances with GitHub Actions enabled, workflows using `actions/github-script@v7` failed with an Internal Server Error during action resolution. In the previous GHES version, the bundled actions/github-script repository referenced a Git object that no longer existed, causing all workflows using `actions/github-script@v7` to fail. + - | + API consumers could not access secret scanning scan history for archived repositories, even when the organization had a GitHub Advanced Security license. + - | + When applying a hotpatch or running a configuration with `ghe-config-apply`, the configuration run could fail with `ERROR: Restoring CodeQL Action release tags` if internal Git services were not yet fully available. The error message `SpokesAPI::TwirpServerError: unavailable` appeared in logs. + - | + On instances connected to GitHub Enterprise Cloud with data residency, the "GitHub.com actions" setting appeared in the GitHub Connect configuration despite this feature not being available for data residency deployments. + - | + On instances with GitHub Actions enabled, errors appeared in logs related to missing Elasticsearch field mappings for workflow runs. The workflow run data included an `archived` field that was not defined in the Elasticsearch index mapping. + - | + The site admin bar displayed debugging information used by GitHub. + - | + Suspended users were listed in an organization's list of members. + - | + Migrations to GitHub Enterprise Server failed when the importer service tried to import a pull request review comment that referenced a garbage-collected commit. Now, these comments are skipped gracefully. + - | + The site admin "All organizations" report included soft-deleted organizations. + - | + On an instance with busy databases, online schema migrations using gh-ost failed because the cut-over lock timeout defaulted to 3 seconds, which was insufficient to acquire an exclusive table lock under continuous traffic. + changes: + - | + Administrators can now set `mysql.innodb-online-alter-log-max-size` with `ghe-config` so the value persists when a configuration is applied or upgraded. + - | + Administrators can configure the maximum number of concurrent HTTP/2 streams per connection for HAProxy. To set this value, use `ghe-config core.haproxy-h2-max-concurrent-streams VALUE` and run `ghe-config-apply`. Previously, this value was hardcoded to 100. + - | + To limit misleading error messages when the `mysql_exporter` and `sql_exporter` exporters try to connect to the database, both exporters use an IPv4 address. + - | + Grafana dashboards on the "Monitor" tab of the Management Console are better labeled and organized. + * Dashboards include a "[collectd]" or "[OpenTelemetry]" prefix based on their monitoring stack. + * The "External MySQL" dashboard is hidden unless External MySQL is enabled. + * OpenTelemetry dashboards have the "opentelemetry" tag, not the "prometheus" tag. + - | + To improve page load performance, user profile pages display a maximum of 24 organizations. When viewing your own profile, a "View all" link provides access to the full list in organization settings. When viewing another user's profile, a count displays any additional organizations beyond the first 24. + known_issues: + - | + First time setups of GitHub Actions with OpenID Connect (OIDC) fail with an error on the `Update Servicing Resources` step. This problem does not affect instances where GitHub Actions is already enabled. + + As a workaround, you can enable Actions without OIDC, then enable OIDC **immediately** once the process completes. You should do this immediately because enabling OIDC will remove all access to existing Actions logs and artifacts. + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [Troubleshooting access to the Management Console](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + On an instance with the HTTP `X-Forwarded-For` header configured for use behind a load balancer, all client IP addresses in the instance's audit log erroneously appear as 127.0.0.1. + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may timeout on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shutdown the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + An organization-level code scanning configuration page is displayed on instances that do not use GitHub Advanced Security or code scanning. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + Admins setting up cluster high availability (HA) may encounter a spokes error when running `ghe-cluster-repl-status` if a new organization and repositories are created before using the `ghe-cluster-repl-bootstrap` command. To avoid this issue, complete the cluster HA setup with `ghe-cluster-repl-bootstrap` before creating new organizations and repositories. + - | + In a cluster, the host running restore requires access the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + Unexpected elements may appear in the UI on the repo overview page for locked repositories. + - | + When publishing npm packages in a workflow after restoring from a backup to GitHub Enterprise Server 3.13.5.gm4 or 3.14.2.gm3, you may encounter a `401 Unauthorized` error from the GitHub Packages service. This can happen if the restore is from an N-1 or N-2 version and the workflow targets the npm endpoint on the backup instance. To avoid this issue, ensure the access token is valid and includes the correct scopes for publishing to GitHub Packages. + - | + The setting to define private registries at the organization level for code scanning is only available if dependabot is also enabled for the instance. + - | + Custom NTP settings are removed during the upgrade process. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. diff --git a/data/release-notes/enterprise-server/3-19/5.yml b/data/release-notes/enterprise-server/3-19/5.yml new file mode 100644 index 000000000000..16de337747c3 --- /dev/null +++ b/data/release-notes/enterprise-server/3-19/5.yml @@ -0,0 +1,131 @@ +date: '2026-04-21' +sections: + security_fixes: + - | + **HIGH**: An attacker could gain unauthorized access to private repositories by abusing scoped user-to-server (`ghu_`) tokens after their associated GitHub App installation was revoked or deleted. In certain cases, the authorization layer could incorrectly fall back to a global installation context instead of rejecting the request, allowing the token to access resources outside its intended installation or repository scope. This issue could be chained with weaknesses in token revocation timing and SSH push attribution to obtain a victim-scoped token and read private repository contents without victim interaction. GitHub has requested CVE ID [CVE-2026-5845](https://www.cve.org/cverecord?id=CVE-2026-5845) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker could extract sensitive environment variables from a GitHub Enterprise Server instance through a timing side-channel attack against the notebook rendering service. When private mode was disabled, the notebook viewer followed HTTP redirects without revalidating the destination host, enabling an unauthenticated Server-Side Request Forgery (SSRF) to internal services. By measuring response time differences, an attacker could infer secret values character by character. GitHub has requested CVE ID [CVE-2026-5921](https://www.cve.org/cverecord?id=CVE-2026-5921) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **HIGH**: A Management Console administrator could inject shell metacharacters into configuration fields via the Management Console configuration API, leading to arbitrary command execution on the appliance as the admin OS user. GitHub has requested CVE ID [CVE-2026-4821](https://www.cve.org/cverecord?id=CVE-2026-4821) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker with knowledge of a target application's registered OAuth callback URL could gain unauthorized access to user accounts by exploiting incorrect regular expression matching in callback URL validation. GitHub has requested CVE ID [CVE-2026-4296](https://www.cve.org/cverecord?id=CVE-2026-4296) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An attacker with permission to manage secret scanning push protection settings in one repository could add or remove delegated bypass reviewers in a different repository by exploiting an incorrect authorization check in the `/settings/security_analysis/bypass_reviewers` endpoints. Authorization was checked against the repository in the URL route, but the action was applied to a different repository specified in the request body. The impact is limited to assigning existing trusted users as bypass reviewers. GitHub has requested CVE ID [CVE-2026-3307](https://www.cve.org/cverecord?id=CVE-2026-3307) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An authenticated attacker could determine the names of private repositories by their numeric ID through the mobile upload policy API endpoint, which returned repository names in validation error messages without verifying the caller's access. GitHub has requested [CVE ID CVE-2026-5512](https://www.cve.org/cverecord?id=CVE-2026-5512) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + Dependabot security update jobs failed silently when dependency groups with `applies-to: security-updates` were configured. + - | + After administrators installed or removed a custom certificate authority (CA) certificate with `ghe-ssl-ca-certificate-install`, Dependabot services continued using the previous CA store and could fail to connect to external registries that required the updated CA. + - | + On an instance with GitHub Actions enabled, diagnostic log files for storage connectivity checks did not persist to disk when site administrators clicked **Test storage settings** in the Management Console or ran `ghe-config-apply` to apply configuration changes. This made storage connection failures difficult to troubleshoot because logs were unavailable in support bundles. + - | + During initial setup of a new instance, site administrators saw an "Oops! A configuration run is already in progress" error message in the Management Console even though `ghe-config-apply` had not been run. + - | + On instances using the new OpenTelemetry-based metrics stack, upgrading the instance re-enabled the legacy collectd-based metrics stack. + - | + Cluster administrators experienced `ghe-config-apply` failures when all replica nodes were marked offline and unreachable. Previously, `ghe-cluster-config-update` attempted to sync configuration files to an empty host list, causing the sync step to fail. + - | + Administrators experienced `ghe-support-bundle` appearing to hang on instances configured for high availability when one or more replica nodes were offline or unreachable during connectivity checks. + - | + When Consul replication failed to start, a misleading error message `exit: check_consul_replication: numeric argument required` was emitted to `ghe-config.log`. + - | + Consul replication would sometimes fail to start and would repeatedly display an error message `WARNING: Consul KV Replication Error` before terminating. + - | + On instances with Dependabot enabled, hotpatch upgrades could lock the Nomad jobs queue. + - | + When site administrators set the `observability.otelcol.gogc-enabled` parameter to a boolean value, the `config-apply` failed. + - | + On instances with GitHub Actions enabled, workflows using `actions/github-script@v7` failed with an Internal Server Error during action resolution. In the previous GHES version, the bundled actions/github-script repository referenced a Git object that no longer existed, causing all workflows using `actions/github-script@v7` to fail. + - | + API consumers could not access secret scanning scan history for archived repositories, even when the organization had a GitHub Advanced Security license. + - | + When applying a hotpatch or running a configuration with `ghe-config-apply`, the configuration run could fail with `ERROR: Restoring CodeQL Action release tags` if internal Git services were not yet fully available. The error message `SpokesAPI::TwirpServerError: unavailable` appeared in logs. + - | + Organization creation failed with a 500 error because the system incorrectly attempted to verify CAPTCHA responses when no CAPTCHA challenge was shown to users. + - | + On instances connected to GitHub Enterprise Cloud with data residency, the "GitHub.com actions" setting appeared in the GitHub Connect configuration despite this feature not being available for data residency deployments. + - | + On instances with GitHub Actions enabled, errors appeared in logs related to missing Elasticsearch field mappings for workflow runs. The workflow run data included an `archived` field that was not defined in the Elasticsearch index mapping. + - | + The site admin bar displayed debugging information used by GitHub. + - | + Suspended users were listed in an organization's list of members. + - | + Migrations to GitHub Enterprise Server failed when the importer service tried to import a pull request review comment that referenced a garbage-collected commit. Now, these comments are skipped gracefully. + - | + An error was raised when attempting to delete an organization. + - | + On instances where the enterprise had set a {% data variables.product.pat_generic %} (PAT) expiration lifetime policy, the policy was not enforced for users who were not affiliated with any organization. Unaffiliated users could use classic PATs beyond the configured expiration limit. The enterprise-wide PAT lifetime policy is now enforced for all users regardless of organization affiliation. + - | + The site admin "All organizations" report included soft-deleted organizations. + - | + Users saw a “Preview” label for secret scanning’s Generic Secrets and Low Confidence Patterns, even though both features were generally available. + - | + On instances that blocked outbound internet access, code scanning repeatedly failed due to unnecessary outbound requests for functionality that is not available on GitHub Enterprise Server. + - | + On an instance with busy databases, online schema migrations using gh-ost failed because the cut-over lock timeout defaulted to 3 seconds, which was insufficient to acquire an exclusive table lock under continuous traffic. + changes: + - | + To improve SSH security, the instance no longer advertises the ssh-rsa signature algorithm (which uses SHA-1) for server host keys on ports 22 and 122. RSA keys continue to work using the more secure rsa-sha2-256 and rsa-sha2-512 signature algorithms. Administrators using very old SSH clients that only support SHA-1 signatures may need to upgrade their clients. For more information about SSH algorithms, see [AUTOTITLE](/admin/configuration/configuring-your-enterprise/configuring-ssh-connections-to-your-instance). + - | + Administrators can now set `mysql.innodb-online-alter-log-max-size` with `ghe-config` so the value persists when a configuration is applied or upgraded. + - | + Administrators can configure the maximum number of concurrent HTTP/2 streams per connection for HAProxy. To set this value, use `ghe-config core.haproxy-h2-max-concurrent-streams VALUE` and run `ghe-config-apply`. Previously, this value was hardcoded to 100. + - | + Grafana dashboards on the "Monitor" tab of the Management Console are better labeled and organized. + * Dashboards include a "[collectd]" or "[OpenTelemetry]" prefix based on their monitoring stack. + * The "External MySQL" dashboard is hidden unless External MySQL is enabled. + * OpenTelemetry dashboards have the "opentelemetry" tag, not the "prometheus" tag. + - | + To limit misleading error messages when the `mysql_exporter` and `sql_exporter` exporters try to connect to the database, both exporters use an IPv4 address. + - | + To improve page load performance, user profile pages display a maximum of 24 organizations. When viewing your own profile, a "View all" link provides access to the full list in organization settings. When viewing another user's profile, a count displays any additional organizations beyond the first 24. + known_issues: + - | + First time setups of GitHub Actions with OpenID Connect (OIDC) fail with an error on the `Update Servicing Resources` step. This problem does not affect instances where GitHub Actions is already enabled. + + As a workaround, you can enable Actions without OIDC, then enable OIDC **immediately** once the process completes. You should do this immediately because enabling OIDC will remove all access to existing Actions logs and artifacts. + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [Troubleshooting access to the Management Console](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may timeout on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shutdown the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + Admins setting up cluster high availability (HA) may encounter a spokes error when running `ghe-cluster-repl-status` if a new organization and repositories are created before using the `ghe-cluster-repl-bootstrap` command. To avoid this issue, complete the cluster HA setup with `ghe-cluster-repl-bootstrap` before creating new organizations and repositories. + - | + In a cluster, the host running restore requires access the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + When publishing npm packages in a workflow after restoring from a backup to GitHub Enterprise Server 3.13.5.gm4 or 3.14.2.gm3, you may encounter a `401 Unauthorized` error from the GitHub Packages service. This can happen if the restore is from an N-1 or N-2 version and the workflow targets the npm endpoint on the backup instance. To avoid this issue, ensure the access token is valid and includes the correct scopes for publishing to GitHub Packages. + - | + The setting to define private registries at the organization level for code scanning is only available if dependabot is also enabled for the instance. + - | + Upgrading or hotpatching to 3.19.1 may fail on nodes that have been continuously upgraded from versions older than 2021 (i.e. 2.17). If this issue occurs, you will see log entries prefixed with `invalid secret` in ghe-config.log. If you are running nodes from these older versions, it is recommended not to upgrade to 3.19.1. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. diff --git a/data/release-notes/enterprise-server/3-20/1.yml b/data/release-notes/enterprise-server/3-20/1.yml new file mode 100644 index 000000000000..3ccfa1fac402 --- /dev/null +++ b/data/release-notes/enterprise-server/3-20/1.yml @@ -0,0 +1,123 @@ +date: '2026-04-21' +sections: + security_fixes: + - | + **HIGH**: An attacker could gain unauthorized access to private repositories by abusing scoped user-to-server (`ghu_`) tokens after their associated GitHub App installation was revoked or deleted. In certain cases, the authorization layer could incorrectly fall back to a global installation context instead of rejecting the request, allowing the token to access resources outside its intended installation or repository scope. This issue could be chained with weaknesses in token revocation timing and SSH push attribution to obtain a victim-scoped token and read private repository contents without victim interaction. GitHub has requested CVE ID [CVE-2026-5845](https://www.cve.org/cverecord?id=CVE-2026-5845) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker could extract sensitive environment variables from a GitHub Enterprise Server instance through a timing side-channel attack against the notebook rendering service. When private mode was disabled, the notebook viewer followed HTTP redirects without revalidating the destination host, enabling an unauthenticated Server-Side Request Forgery (SSRF) to internal services. By measuring response time differences, an attacker could infer secret values character by character. GitHub has requested CVE ID [CVE-2026-5921](https://www.cve.org/cverecord?id=CVE-2026-5921) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **HIGH**: A Management Console administrator could inject shell metacharacters into configuration fields via the Management Console configuration API, leading to arbitrary command execution on the appliance as the admin OS user. GitHub has requested CVE ID [CVE-2026-4821](https://www.cve.org/cverecord?id=CVE-2026-4821) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker with knowledge of a target applications registered OAuth callback URL could gain unauthorized access to user accounts by exploiting incorrect regular expression matching in callback URL validation. GitHub has requested CVE ID [CVE-2026-4296](https://www.cve.org/cverecord?id=CVE-2026-4296) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **HIGH**: An attacker without write access could merge their own pull request into a repository that allowed forks by exploiting an incorrect authorization check in the `enable_auto_merge` mutation for pull requests. Exploitation required a clean pull request status and only applied to branches without branch protection rules enabled. GitHub has requested CVE ID [CVE-2026-1999](https://www.cve.org/cverecord?id=CVE-2026-1999) for this vulnerability, which was reported via the [GitHub Bug Bounty](https://bounty.github.com/) program. + - | + **MEDIUM**: An attacker with permission to manage secret scanning push protection settings in one repository could add or remove delegated bypass reviewers in a different repository by exploiting an incorrect authorization check in the `/settings/security_analysis/bypass_reviewers` endpoints. Authorization was checked against the repository in the URL route, but the action was applied to a different repository specified in the request body. The impact is limited to assigning existing trusted users as bypass reviewers. GitHub has requested CVE ID [CVE-2026-3307](https://www.cve.org/cverecord?id=CVE-2026-3307) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM**: An authenticated attacker could determine the names of private repositories by their numeric ID through the mobile upload policy API endpoint, which returned repository names in validation error messages without verifying the caller's access. GitHub has requested [CVE ID CVE-2026-5512](https://www.cve.org/cverecord?id=CVE-2026-5512) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **LOW**: An attacker could create or modify organization rulesets because Security Managers had unintended access. To mitigate this issue, GitHub updated role-based access controls to prevent Security Managers from changing rulesets. This vulnerability was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + Dependabot security updates now work correctly for repositories using grouped security updates on GHES. Previously, an incorrect internal API URL caused security update jobs to fail silently when dependency groups with `applies-to: security-updates` were configured. + - | + After administrators installed or removed a custom certificate authority (CA) certificate with `ghe-ssl-ca-certificate-install`, Dependabot services continued using the previous CA store and could fail to connect to external registries that required the updated CA. + - | + On an instance with GitHub Actions enabled, diagnostic log files for storage connectivity checks did not persist to disk when site administrators clicked **Test storage settings** in the management console or ran `ghe-config-apply` to apply configuration changes. This made storage connection failures difficult to troubleshoot because logs were unavailable in support bundles. + - | + During initial setup of a new instance, site administrators saw an "Oops! A configuration run is already in progress" error message in the Management Console even though `ghe-config-apply` had not been run. + - | + On instances using the new OpenTelemetry-based metrics stack, upgrading the instance re-enabled the legacy collectd-based metrics stack. + - | + Cluster administrators experienced `ghe-config-apply` failures when all replica nodes were marked offline and unreachable. Previously, `ghe-cluster-config-update` attempted to sync configuration files to an empty host list, causing the sync step to fail. + - | + Administrators experienced `ghe-support-bundle` appearing to hang on instances configured for high availability when one or more replica nodes were offline or unreachable during connectivity checks. + - | + When Consul replication fails to start, a misleading error message `exit: check_consul_replication: numeric argument required` would be emitted to ghe-config.log. + - | + On instances with Dependabot enabled, hotpatch upgrades could lock the Nomad jobs queue. + - | + When site administrators set the `observability.otelcol.gogc-enabled` parameter to a boolean value, the `config-apply` failed. + - | + API consumers could not access secret scanning scan history for archived repositories, even when the organization had a GitHub Advanced Security license. + - | + When applying a hotpatch or running a configuration with `ghe-config-apply`, the configuration run could fail with "ERROR: Restoring CodeQL Action release tags" if internal Git services were not yet fully available. The error message "SpokesAPI::TwirpServerError: unavailable" appeared in logs. + - | + On instances connected to GitHub Enterprise Cloud with data residency, the "GitHub.com actions" setting appeared in the GitHub Connect configuration despite this feature not being available for data residency deployments. + - | + On instances with GitHub Actions enabled, errors appeared in logs related to missing Elasticsearch field mappings for workflow runs. The workflow run data included an `archived` field that was not defined in the Elasticsearch index mapping. + - | + The GitHub Enterprise Server staffbar was displaying debugging information used by GitHub. + - | + On an instance with a GitHub Advanced Security license, searching for assignees in secret scanning alerts did not return results for users with write access if the repository had more than 1500 eligible users. + - | + Suspended users were listed in an organizations list of members. + - | + Migrations to GitHub Enterprise Server failed when the importer service tried to import a pull request review comment that referenced a garbage-collected commit. Now, these comments are skipped gracefully. + - | + After an instance upgraded to a previous patch release in this series, some users dashboard RSS/Atom feeds (`/:login.private.atom`) returned an empty feed with no entries, and users could not subscribe to the feed. Dashboard feeds now return entries as expected. + - | + The site admin "All organizations" report included soft-deleted organizations. + - | + Users saw a “Preview” label for secret scanning’s Generic Secrets and Low Confidence Patterns, even though both features were generally available. + - | + On instances that blocked outbound internet access, code scanning repeatedly failed due to unnecessary outbound requests for functionality that is not available on GitHub Enterprise Server. + changes: + - | + To improve SSH security, the instance no longer advertises the ssh-rsa signature algorithm (which uses SHA-1) for server host keys on ports 22 and 122. RSA keys continue to work using the more secure rsa-sha2-256 and rsa-sha2-512 signature algorithms. Administrators using very old SSH clients that only support SHA-1 signatures may need to upgrade their clients. For more information about SSH algorithms, see [AUTOTITLE](https://github.com/admin/configuration/configuring-your-enterprise/configuring-ssh-connections-to-your-instance). + - | + Administrators can now set `mysql.innodb-online-alter-log-max-size` with `ghe-config` so the value persists when a configuration is applied or upgraded. + - | + Administrators can configure the maximum number of concurrent HTTP/2 streams per connection for HAProxy. To set this value, use `ghe-config core.haproxy-h2-max-concurrent-streams VALUE` and run `ghe-config-apply`. Previously, this value was hardcoded to 100. + - | + Grafana dashboards on the "Monitor" tab of the Management Console are better labeled and organized. + * Dashboards include a "[collectd]" or "[OpenTelemetry]" prefix based on their monitoring stack. + * The "External MySQL" dashboard is hidden unless External MySQL is enabled. + * OpenTelemetry dashboards have the "opentelemetry" tag, not the "prometheus" tag. + - | + To limit misleading error messages when the `mysql_exporter` and `sql_exporter` exporters try to connect to the database, both exporters use an IPv4 address. + - | + On an instance with busy databases, online schema migrations using gh-ost failed because the cut-over lock timeout defaulted to 3 seconds, which was insufficient to acquire an exclusive table lock under continuous traffic. + - | + When creating a new organization, members who already have access through enterprise teams are no longer listed individually on the invite page. A banner is shown instead, with a link to manage enterprise team access. + - | + To improve page load performance, user profile pages display a maximum of 24 organizations. When viewing your own profile, a "View all" link provides access to the full list in organization settings. When viewing another users profile, a count displays any additional organizations beyond the first 24. + known_issues: + - | + First time setups of GitHub Actions with OpenID Connect (OIDC) fail with an error on the `Update Servicing Resources` step. This problem does not affect instances where GitHub Actions is already enabled. + + As a workaround, you can enable Actions without OIDC, then enable OIDC **immediately** once the process completes. You should do this immediately because enabling OIDC will remove all access to existing Actions logs and artifacts. + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [Troubleshooting access to the Management Console](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may timeout on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shutdown the node and repeat the steps. + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + Admins setting up cluster high availability (HA) may encounter a spokes error when running `ghe-cluster-repl-status` if a new organization and repositories are created before using the `ghe-cluster-repl-bootstrap` command. To avoid this issue, complete the cluster HA setup with `ghe-cluster-repl-bootstrap` before creating new organizations and repositories. + - | + In a cluster, the host running restore requires access the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + When publishing npm packages in a workflow after restoring from a backup to GitHub Enterprise Server 3.13.5.gm4 or 3.14.2.gm3, you may encounter a `401 Unauthorized` error from the GitHub Packages service. This can happen if the restore is from an N-1 or N-2 version and the workflow targets the npm endpoint on the backup instance. To avoid this issue, ensure the access token is valid and includes the correct scopes for publishing to GitHub Packages. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. + - | + In GHES instances that have multiple git storage nodes in a voting configurations (That includes GHES Clusters and Geo Replicate HA instances) where Actions is enabled can encounter problem a upon upgrading. The 1st part actions that are shipped with the new version of GHES can not be correctly installed. This can block upgrade and in some cases leave the old versions of these actions within the instatance. diff --git a/data/reusables/actions/action-checkout.md b/data/reusables/actions/action-checkout.md index 9fd8f0315cd5..63dad67b00ef 100644 --- a/data/reusables/actions/action-checkout.md +++ b/data/reusables/actions/action-checkout.md @@ -1 +1 @@ -actions/checkout@v5 +actions/checkout@v6 diff --git a/data/reusables/copilot/custom-agents-configuring-profile.md b/data/reusables/copilot/custom-agents-configuring-profile.md new file mode 100644 index 000000000000..0149e1df0e16 --- /dev/null +++ b/data/reusables/copilot/custom-agents-configuring-profile.md @@ -0,0 +1,13 @@ +An {% data variables.copilot.agent_profile %} is a Markdown file with YAML frontmatter that specifies the {% data variables.copilot.copilot_custom_agent_short %}'s name, description, available tools, and MCP server configurations. Configuring an {% data variables.copilot.agent_profile %} involves defining the agent's identity, capabilities, tool access, and behavioral instructions. + +For detailed configuration information about YAML properties, tools, MCP server setup, tool aliases, and how {% data variables.copilot.custom_agents_short %} are processed, see [AUTOTITLE](/copilot/reference/custom-agents-configuration). + +To configure your {% data variables.copilot.agent_profile %}: + +1. Optionally, write a `name` for your {% data variables.copilot.copilot_custom_agent_short %}. If unset, the name will default to the filename (without the `.md` or `.agent.md` suffix). +1. Write a brief `description` (required) explaining what your agent does and its specific capabilities or domain expertise. +1. In the `tools` property, define which tools the agent can use. This is a list of tool names or aliases, including tools from MCP servers configured in the repository settings or the {% data variables.copilot.agent_profile %} (for example, `tools: ["read", "edit", "search", "some-mcp-server/tool-1"]`). If you omit this property, the agent will have access to all available tools. See "Tools" in [AUTOTITLE](/copilot/reference/custom-agents-configuration#tools). +1. Optionally, in the `mcp-servers` property, you can configure MCP servers that will be available only to this agent to extend its capabilities. See "MCP server configuration details" in [AUTOTITLE](/copilot/reference/custom-agents-configuration#mcp-server-configuration-details). +1. If you are creating and using the {% data variables.copilot.agent_profile %} in {% data variables.product.prodname_vscode_shortname %}, JetBrains IDEs, Eclipse, or Xcode, you can also use the `model` property to control which AI model the agent should use. +1. Optionally, set the `target` property to either `vscode` or `github-copilot` if you want to only use the agent in a specific environment. The agent will be available in both environments if you omit the property. +1. Write the agent's prompt. Define the agent's behavior, expertise, and instructions in the Markdown content below the YAML frontmatter. The prompt can be a maximum of 30,000 characters. diff --git a/data/reusables/copilot/custom-agents-next-steps.md b/data/reusables/copilot/custom-agents-next-steps.md new file mode 100644 index 000000000000..94a40853352c --- /dev/null +++ b/data/reusables/copilot/custom-agents-next-steps.md @@ -0,0 +1,3 @@ +* For a hands-on tutorial to create your first {% data variables.copilot.copilot_custom_agent_short %}, see [AUTOTITLE](/copilot/tutorials/customization-library/custom-agents/your-first-custom-agent). +* For detailed configuration information, see [AUTOTITLE](/copilot/reference/custom-agents-configuration). +* For information on using cloud agents, including your {% data variables.copilot.custom_agents_short %}, to create pull requests, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/create-a-pr). diff --git a/data/reusables/copilot/custom-agents-using.md b/data/reusables/copilot/custom-agents-using.md new file mode 100644 index 000000000000..bb5194b0f6fd --- /dev/null +++ b/data/reusables/copilot/custom-agents-using.md @@ -0,0 +1,9 @@ +Once you've created a {% data variables.copilot.copilot_custom_agent_short %}, you can use it wherever {% data variables.copilot.copilot_cloud_agent %} is available. + +* When prompting {% data variables.copilot.copilot_cloud_agent %} with a task on {% data variables.product.prodname_dotcom_the_website %}, use the dropdown menu in the agents panel or agents tab to select your {% data variables.copilot.copilot_custom_agent_short %} instead of the default {% data variables.copilot.copilot_cloud_agent_short %}. +* When assigning {% data variables.copilot.copilot_cloud_agent %} to an issue, you can select your {% data variables.copilot.copilot_custom_agent_short %} from the dropdown menu to handle the issue with your specialized configuration. +* When using the {% data variables.copilot.copilot_cli %}, you can choose to use a particular {% data variables.copilot.copilot_custom_agent_short %} by using the `/agent` slash command or referencing the agent in a prompt or via a command-line argument. For more information, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/use-copilot-cli#use-custom-agents). + +When {% data variables.product.prodname_copilot_short %} opens pull requests, it will note which {% data variables.copilot.copilot_custom_agent_short %} was used to complete the work in the pull request description. + +For more information on using {% data variables.copilot.copilot_cloud_agent %}, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/cloud-agent/create-a-pr). diff --git a/src/languages/lib/correct-translation-content.ts b/src/languages/lib/correct-translation-content.ts index 2e1eb3fed434..7730a196b5b4 100644 --- a/src/languages/lib/correct-translation-content.ts +++ b/src/languages/lib/correct-translation-content.ts @@ -20,6 +20,53 @@ export function correctTranslatedContentStrings( englishContent: string, context: CorrectionContext = {}, ): string { + // --- Universal pre-fixes (run before per-language rules) --- + + // Translators sometimes inserted spaces inside Liquid delimiters, + // breaking the tags (e.g. `{ % endif %}`, `{% endif % }`). Collapse + // these — but only when the tag has actual non-whitespace content + // inside, so we don't disturb the special `{% }` → `{% endif %}` + // recovery handled later. The English source never contains these + // patterns, so this is safe globally. + content = content.replace(/\{\s*%(-?)(\s*\S[^%]*?\s*)(-?)%\s*\}/g, '{%$1$2$3%}') + + // Translators sometimes dropped the `data` keyword in front of a + // `variables.X.Y` / `reusables.X.Y` / `product.X` path. The English + // source never starts a Liquid tag with these prefixes; they always + // come inside `{% data variables.X %}` or similar. Restore the keyword. + content = content.replace( + /\{%(-?)\s+(variables|reusables)\.([A-Za-z0-9._-]+)(\s*-?%\})/g, + '{%$1 data $2.$3$4', + ) + // `{% product.prodname_X %}` → `{% data variables.product.prodname_X %}` + content = content.replace( + /\{%(-?)\s+(product\.[A-Za-z0-9._-]+)(\s*-?%\})/g, + '{%$1 data variables.$2$3', + ) + + // Translators sometimes wrote `{% data.variables.X %}` (period instead + // of space) or `{% data.reusables.X %}` / `{% data.product.X %}`, + // which Liquid parses as a single variable lookup whose name starts + // with `.variables` / `.reusables`. Restore the space. + content = content.replace( + /\{%(-?)\s*data\.(variables|reusables)\.([A-Za-z0-9._-]+)(\s*-?%\})/g, + '{%$1 data $2.$3$4', + ) + content = content.replace( + /\{%(-?)\s*data\.(product\.[A-Za-z0-9._-]+)(\s*-?%\})/g, + '{%$1 data variables.$2$3', + ) + + // The translation pipeline frequently splits Markdown bullet markers + // (`*`) and table-cell pipes (`|`) onto their own line, with the + // actual content pushed to the next line as deeply indented text. + // This breaks list and table rendering and leaves `[AUTOTITLE]` links + // unexpanded. Rejoin the marker with its content. This corruption + // affects every translated language (~47k bullets and ~11k cells in + // total), so it lives in the universal pre-fixes block. + content = content.replace(/^\* ?\n[ \t]+/gm, '* ') + content = content.replace(/^\|[ \t]*\n[ \t]+/gm, '| ') + // --- Per-language fixes (es, ja, pt, zh, ru, fr, ko, de) --- if (context.code === 'es') { @@ -102,6 +149,20 @@ export function correctTranslatedContentStrings( // `{% encabezados de fila %}` — "row headers" = rowheaders content = content.replaceAll('{% encabezados de fila %}', '{% rowheaders %}') content = content.replaceAll('{%- encabezados de fila %}', '{%- rowheaders %}') + // Spanish `o` = "or", `y` = "and" inside ifversion/elsif/if + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\so\s[^%]*?-?%\}/g, (m) => + m.replace(/\so\s/g, ' or '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\sy\s[^%]*?-?%\}/g, (m) => + m.replace(/\sy\s/g, ' and '), + ) + // `{% ifversion ghes}` (missing `%` before `}`) — translator dropped the + // closing percent. Match plan name (fpt|ghec|ghes|ghae) followed by `}` + // not `%}`, immediately followed by content (so we don't over-match). + content = content.replace( + /\{%-?(\s+(?:ifversion|elsif|if)\s+(?:not\s+)?(?:fpt|ghec|ghes|ghae)(?:\s+(?:or|and)\s+(?:not\s+)?(?:fpt|ghec|ghes|ghae))*)\}/g, + '{%$1 %}', + ) } if (context.code === 'ja') { @@ -236,6 +297,74 @@ export function correctTranslatedContentStrings( // `{% ウィンドウ %}` — "Window" (without ズ suffix) = windows (alternate transliteration) content = content.replaceAll('{% ウィンドウ %}', '{% windows %}') content = content.replaceAll('{%- ウィンドウ %}', '{%- windows %}') + // `{% デスクトップ %}` — "desktop" (Japanese transliteration) = desktop platform tag + content = content.replaceAll('{% デスクトップ %}', '{% desktop %}') + content = content.replaceAll('{%- デスクトップ %}', '{%- desktop %}') + // `{%データ` (no space after `{%`) — also catches `{%データvariables` + content = content.replaceAll('{%データvariables', '{% data variables') + content = content.replaceAll('{%データ variables', '{% data variables') + content = content.replaceAll('{%- データvariables', '{%- data variables') + content = content.replaceAll('{%- データ variables', '{%- data variables') + content = content.replaceAll('{%- データ reusables', '{%- data reusables') + // `{% データ` followed by `.` (path operator) — translator dropped `variables`/`reusables` + content = content.replaceAll('{% データ.variables.', '{% data variables.') + content = content.replaceAll('{% データ.reusables.', '{% data reusables.') + // Generic Japanese `データ` data-tag normalizer. + // Matches `{%[-]?[ ]?データ[ ]?[再利用可能|再利用|変数|reusables|variables|...].PATH %}` + // and rewrites to `{%[-]? data .PATH %}` based on the keyword. + content = content.replace( + /\{%(-?)\s*データ\s*(再利用可能な?|再利用|reusables)\.([^\s%]+)\s*(-?)%\}/g, + (_m, dashOpen, _kw, path, dashClose) => `{%${dashOpen} data reusables.${path} ${dashClose}%}`, + ) + content = content.replace( + /\{%(-?)\s*データ\s*(変数|variables)\.([^\s%]+)\s*(-?)%\}/g, + (_m, dashOpen, _kw, path, dashClose) => `{%${dashOpen} data variables.${path} ${dashClose}%}`, + ) + // Bare `{%データ` / `{%- データ` followed by space + (variables|reusables) + content = content.replace( + /\{%(-?)\s*データ\s+(variables|reusables)\.([^\s%]+)\s*(-?)%\}/g, + (_m, dashOpen, kw, path, dashClose) => `{%${dashOpen} data ${kw}.${path} ${dashClose}%}`, + ) + // `{% メモ` capitalized variant + content = content.replaceAll('{% メモ -%}', '{%- note -%}') + content = content.replaceAll('{%- メモ -%}', '{%- note -%}') + // `{% ノート %}` — alternate Japanese for "note" + content = content.replaceAll('{% ノート %}', '{% note %}') + content = content.replaceAll('{%- ノート %}', '{%- note %}') + // `{% 終わり %}` / `{% 終了 %}` — Japanese "end" used as endif + content = content.replaceAll('{% 終わり %}', '{% endif %}') + content = content.replaceAll('{%- 終わり %}', '{%- endif %}') + content = content.replaceAll('{% 終了 %}', '{% endif %}') + content = content.replaceAll('{%- 終了 %}', '{%- endif %}') + // `{% 終了for %}` / `{% endforの場合 %}` — endfor variants + content = content.replaceAll('{% 終了for %}', '{% endfor %}') + content = content.replaceAll('{%- 終了for %}', '{%- endfor %}') + // Japanese `または` = "or", `かつ` / `および` = "and" inside ifversion/elsif/if + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?または[^%]*?-?%\}/g, (m) => + m.replace(/\s*または\s*/g, ' or '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?かつ[^%]*?-?%\}/g, (m) => + m.replace(/\s*かつ\s*/g, ' and '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?および[^%]*?-?%\}/g, (m) => + m.replace(/\s*および\s*/g, ' and '), + ) + // `{% 行ヘッダー %}` — "row headers" = rowheaders + content = content.replaceAll('{% 行ヘッダー %}', '{% rowheaders %}') + content = content.replaceAll('{%- 行ヘッダー %}', '{%- rowheaders %}') + // `{% 終了行ヘッダー %}` — "end row headers" = endrowheaders + content = content.replaceAll('{% 終了行ヘッダー %}', '{% endrowheaders %}') + content = content.replaceAll('{%- 終了行ヘッダー %}', '{%- endrowheaders %}') + // `{% ウィンドウ %}` / `{% ウィンドウズ %}` — "window/windows" = windows + content = content.replaceAll('{% ウィンドウ %}', '{% windows %}') + content = content.replaceAll('{%- ウィンドウ %}', '{%- windows %}') + content = content.replaceAll('{% ウィンドウズ %}', '{% windows %}') + content = content.replaceAll('{%- ウィンドウズ %}', '{%- windows %}') + // `{% Windowsターミナル %}` / `{% Windows ターミナル %}` — Windows terminal + content = content.replaceAll('{% Windowsターミナル %}', '{% windows %}') + content = content.replaceAll('{% Windows ターミナル %}', '{% windows %}') + // `{% indented_data_reference 再利用可能.X.Y spaces=N %}` — translated path + content = content.replace(/(\{%-?\s*indented_data_reference\s+)再利用可能\./g, '$1reusables.') } if (context.code === 'pt') { @@ -299,6 +428,96 @@ export function correctTranslatedContentStrings( '{% dados agrupados por categoria.complemento.audit_log.reference-grouped-by-category %}', '{% data reusables.audit_log.reference-grouped-by-category %}', ) + // Portuguese decimal comma in version numbers inside ifversion/elsif tags: `3,16` → `3.16` + content = content.replace(/\{%-? (?:ifversion|elsif) [^%]*?%\}/g, (match) => { + return match.replace(/(\d),(\d)/g, '$1.$2') + }) + // `{% para X em Y %}` — Portuguese "for X in Y" + content = content.replace(/\{%-? para (\w+) em /g, (match) => { + return match.replace(/para (\w+) em /, 'for $1 in ') + }) + // `{% reutilizáveis.X.Y %}` — translated reusables path with no `data` prefix + content = content.replaceAll('{% reutilizáveis.', '{% data reusables.') + content = content.replaceAll('{%- reutilizáveis.', '{%- data reusables.') + // `{% dados reusáveis.X.Y %}` — alternate Portuguese spelling for "reusables" + content = content.replaceAll('{% dados reusáveis.', '{% data reusables.') + content = content.replaceAll('{%- dados reusáveis.', '{%- data reusables.') + // `{% reusáveis.X.Y %}` — alternate without `data` prefix + content = content.replaceAll('{% reusáveis.', '{% data reusables.') + content = content.replaceAll('{%- reusáveis.', '{%- data reusables.') + // `{% dados.reutilizáveis.X.Y %}` — translator used `.` instead of space between + // "dados" (data) and "reutilizáveis" (reusables) + content = content.replaceAll('{% dados.reutilizáveis.', '{% data reusables.') + content = content.replaceAll('{%- dados.reutilizáveis.', '{%- data reusables.') + // `{% dados.reusáveis.` — same with alternate spelling + content = content.replaceAll('{% dados.reusáveis.', '{% data reusables.') + content = content.replaceAll('{%- dados.reusáveis.', '{%- data reusables.') + // `{% de data X` — translator inserted Portuguese preposition "de" (of/from) + // before `data variables` / `data reusables` + content = content.replaceAll('{% de data variables', '{% data variables') + content = content.replaceAll('{%- de data variables', '{%- data variables') + content = content.replaceAll('{% de data reusables', '{% data reusables') + content = content.replaceAll('{%- de data reusables', '{%- data reusables') + content = content.replaceAll('{% de dados reusables', '{% data reusables') + // `{% datavariables` — no space between "data" and "variables" (sometimes survives) + content = content.replaceAll('{% datavariables', '{% data variables') + content = content.replaceAll('{%- datavariables', '{%- data variables') + // `{% datas variables` / `{% datas reusables` — plural Portuguese form of "data" + content = content.replaceAll('{% datas variables', '{% data variables') + content = content.replaceAll('{%- datas variables', '{%- data variables') + content = content.replaceAll('{% datas reusables', '{% data reusables') + content = content.replaceAll('{%- datas reusables', '{%- data reusables') + // Word-order swap inside ifversion: `{% ghes ifversion %}` → `{% ifversion ghes %}` + content = content.replace( + /\{%(-?)\s*(fpt|ghec|ghes)\s+ifversion\s*%\}/g, + '{%$1 ifversion $2 %}', + ) + // With extra "de" word: `{% ghes de ifversion %}` → `{% ifversion ghes %}` + content = content.replace( + /\{%(-?)\s*(fpt|ghec|ghes)\s+de\s+ifversion\s*%\}/g, + '{%$1 ifversion $2 %}', + ) + // Mangled order: `{% %} de ghec ifversion` → `{% ifversion ghec %}` + content = content.replaceAll('{% %} de ghec ifversion', '{% ifversion ghec %}') + content = content.replaceAll('{% %} de ghes ifversion', '{% ifversion ghes %}') + content = content.replaceAll('{% %} de fpt ifversion', '{% ifversion fpt %}') + // `{% referência_dados_indentados ` — Portuguese translation of `indented_data_reference` + content = content.replaceAll('{% referência_dados_indentados ', '{% indented_data_reference ') + content = content.replaceAll('{%- referência_dados_indentados ', '{%- indented_data_reference ') + // Broad fallback: any remaining `{% dados ` / `{% Dados ` → `{% data ` + content = content.replace(/\{%(-?)\s*[Dd]ados\s+/g, '{%$1 data ') + // After broad fallback, translated path segments may remain. Catch the most common. + content = content.replace(/\{%(-?\s*)data reutilizáveis\./g, '{%$1data reusables.') + content = content.replace(/\{%(-?\s*)data variáveis\./g, '{%$1data variables.') + // `{% reutilizáveis.` / `{% variáveis.` (no `data` prefix) → add data + content = content.replace(/\{%(-?\s*)reutilizáveis\./g, '{%$1data reusables.') + content = content.replace(/\{%(-?\s*)variáveis\./g, '{%$1data variables.') + // Portuguese `ou` = "or" / `e` = "and" inside ifversion/elsif/if tags + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\sou\s[^%]*?-?%\}/g, (m) => + m.replace(/\sou\s/g, ' or '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\se\s[^%]*?-?%\}/g, (m) => + m.replace(/\se\s/g, ' and '), + ) + // `{% senão %}` / `{% Senão %}` — Portuguese "else" + content = content.replaceAll('{% senão %}', '{% else %}') + content = content.replaceAll('{%- senão %}', '{%- else %}') + content = content.replaceAll('{% Senão %}', '{% else %}') + content = content.replaceAll('{% senao %}', '{% else %}') + content = content.replaceAll('{%- senao %}', '{%- else %}') + // `{% senão se ` / `{% senao se ` — "else if" = elsif + content = content.replaceAll('{% senão se ', '{% elsif ') + content = content.replaceAll('{%- senão se ', '{%- elsif ') + content = content.replaceAll('{% senao se ', '{% elsif ') + // `{% caso contrário %}` — alternate "otherwise" = else + content = content.replaceAll('{% caso contrário %}', '{% else %}') + content = content.replaceAll('{%- caso contrário %}', '{%- else %}') + // `{% observação %}` — "note" = note + content = content.replaceAll('{% observação %}', '{% note %}') + content = content.replaceAll('{%- observação %}', '{%- note %}') + // `{% modelo %}` / `{% modelo` — `template` (alias for `tool`)? Actually "modelo" + // appears as `{% modelo %}` orphaned. Drop unmatched bare `{% modelo %}` is + // risky; instead, leave as-is (Liquid will raise but rare). } if (context.code === 'zh') { @@ -323,10 +542,13 @@ export function correctTranslatedContentStrings( // Stray Chinese `,则为` ("then") merged with `{%` before HTML: `,则为 {%` → `` // The regex consumes the `<` to avoid producing a double `<<`. content = content.replace(/,则为 \{% { - return match.replace(/ 或 /g, ' or ') - }) + // Catch "或" / "和" between any plan names in ifversion/elsif/if tags + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?或[^%]*?-?%\}/g, (m) => + m.replace(/\s*或\s*/g, ' or '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?和[^%]*?-?%\}/g, (m) => + m.replace(/\s*和\s*/g, ' and '), + ) // `{% 行标题 %}` — "row headers" = rowheaders content = content.replaceAll('{% 行标题 %}', '{% rowheaders %}') content = content.replaceAll('{%- 行标题 %}', '{%- rowheaders %}') @@ -337,6 +559,52 @@ export function correctTranslatedContentStrings( content = content.replaceAll('{%- Windows 操作系统 %}', '{%- windows %}') // `{% Windows终端 %}` — "Windows terminal" = windows platform tag content = content.replaceAll('{% Windows终端 %}', '{% windows %}') + // `{% 桌面 %}` — Chinese "desktop" = desktop platform tag + content = content.replaceAll('{% 桌面 %}', '{% desktop %}') + content = content.replaceAll('{%- 桌面 %}', '{%- desktop %}') + // `{% 行标头 %}` / `{% 行标题 %}` — alternate Chinese for "row headers" + content = content.replaceAll('{% 行标头 %}', '{% rowheaders %}') + content = content.replaceAll('{%- 行标头 %}', '{%- rowheaders %}') + content = content.replaceAll('{% 行标题 %}', '{% rowheaders %}') + content = content.replaceAll('{%- 行标题 %}', '{%- rowheaders %}') + // `{% 结束行标题 %}` / `{% 结束行标头 %}` / `{% 结束行头 %}` — endrowheaders + content = content.replaceAll('{% 结束行标题 %}', '{% endrowheaders %}') + content = content.replaceAll('{%- 结束行标题 %}', '{%- endrowheaders %}') + content = content.replaceAll('{% 结束行标头 %}', '{% endrowheaders %}') + content = content.replaceAll('{%- 结束行标头 %}', '{%- endrowheaders %}') + content = content.replaceAll('{% 结束行头 %}', '{% endrowheaders %}') + content = content.replaceAll('{%- 结束行头 %}', '{%- endrowheaders %}') + // `{% 行标题结束 %}` — order swap (rowheaders + end) + content = content.replaceAll('{% 行标题结束 %}', '{% endrowheaders %}') + content = content.replaceAll('{%- 行标题结束 %}', '{%- endrowheaders %}') + // Capitalized `{% Variables.X %}` / `{% Reusables.X %}` — translator title-cased + content = content.replaceAll('{% data Variables.', '{% data variables.') + content = content.replaceAll('{% data Reusables.', '{% data reusables.') + content = content.replaceAll('{%- data Variables.', '{%- data variables.') + content = content.replaceAll('{%- data Reusables.', '{%- data reusables.') + // `{% 否则如果 ` — "otherwise if" = elsif + content = content.replaceAll('{% 否则如果 ', '{% elsif ') + content = content.replaceAll('{%- 否则如果 ', '{%- elsif ') + // `{% 结束 %}` / `{% 结尾 %}` — Chinese "end" = endif + content = content.replaceAll('{% 结束 %}', '{% endif %}') + content = content.replaceAll('{%- 结束 %}', '{%- endif %}') + content = content.replaceAll('{% 结尾 %}', '{% endif %}') + content = content.replaceAll('{%- 结尾 %}', '{%- endif %}') + // `{% 结束for %}` — end + for + content = content.replaceAll('{% 结束for %}', '{% endfor %}') + content = content.replaceAll('{%- 结束for %}', '{%- endfor %}') + // `{% 结束if %}` / `{% endif的话 %}` — endif variants + content = content.replaceAll('{% 结束if %}', '{% endif %}') + content = content.replaceAll('{%- 结束if %}', '{%- endif %}') + // Broad fallback: any remaining `{% 数据 ` → `{% data ` + content = content.replace(/\{%(-?)\s*数据\s+/g, '{%$1 data ') + // `{% indented_data_reference 可重用|可复用|可重用项|可重用组件|可复用项.X.Y spaces=N %}` + // — translator converted the `reusables` path prefix into Chinese. Collapse + // any `可(重|复)用[项|组件|s]?.` prefix into `reusables.`. + content = content.replace( + /(\{%-?\s*indented_data_reference\s+)可(?:重|复)用(?:项|组件|s)?\./g, + '$1reusables.', + ) } if (context.code === 'ru') { @@ -380,6 +648,10 @@ export function correctTranslatedContentStrings( content = content.replace(/\{%-? (?:ifversion|elsif|if) [^%]*?или[^%]*?%\}/g, (match) => { return match.replace(/ или /g, ' or ') }) + // Russian decimal comma in version numbers inside ifversion/elsif tags: `3,18` → `3.18` + content = content.replace(/\{%-? (?:ifversion|elsif) [^%]*?%\}/g, (match) => { + return match.replace(/(\d),(\d)/g, '$1.$2') + }) content = content.replaceAll('{% конечным %}', '{% endif %}') content = content.replaceAll('{%- конечным %}', '{%- endif %}') // `{%- конец %}` — dash-trimmed form of "end" = endif @@ -421,6 +693,14 @@ export function correctTranslatedContentStrings( content = content.replaceAll('{%- примечание %}', '{%- note %}') content = content.replaceAll('{% конечных головщиков %}', '{% endrowheaders %}') content = content.replaceAll('{% данных для повторного использования.', '{% data reusables.') + // `{% indented_data_reference повторн... .X.Y spaces=N %}` — translator + // converted the `reusables` path prefix into Russian (with spaces inside), + // which breaks the indented_data_reference parser. Collapse any + // `повторн[...][ ]*.` prefix into `reusables.`. + content = content.replace( + /(\{%-?\s*indented_data_reference\s+)повторн[а-яё]*(?:\s+[а-яё]+)*\./g, + '$1reusables.', + ) content = content.replaceAll('{% еще %}', '{% else %}') content = content.replaceAll('{%- еще %}', '{%- else %}') content = content.replaceAll('{% ещё %}', '{% else %}') @@ -476,9 +756,102 @@ export function correctTranslatedContentStrings( '{% octicon "организация" aria-hidden="true" aria-label="organization" %}', '{% octicon "organization" aria-hidden="true" aria-label="organization" %}', ) + // `{% Эльсиф CONDITION %}` — transliteration of "elsif" with a condition + content = content.replace(/\{%(-?)\s*Эльсиф\s+/g, '{%$1 elsif ') + // `{% для X в Y %}` — Russian "for X in Y" + content = content.replace(/\{%-?\s*для\s+(\w+)\s+в\s+/g, (match) => { + const dash = match.startsWith('{%-') ? '{%-' : '{%' + return match.replace(/^\{%-?\s*для\s+(\w+)\s+в\s+/, `${dash} for $1 in `) + }) + // `, а не ghes` — Russian "and not ghes" inside ifversion expressions + content = content.replace(/\{%-? (?:ifversion|elsif|if) [^%]*?, а не [^%]*?%\}/g, (match) => { + return match.replace(/, а не /g, ' and not ') + }) + // `{% ifversion ghes не ` — `не` ("not") inside ifversion + content = content.replace(/\{%-? (?:ifversion|elsif|if) [^%]*?\sне\s[^%]*?%\}/g, (match) => { + return match.replace(/ не /g, ' not ') + }) + // `aria-label="autoTITLE"` — "AUTOTITLE" was lowercased by translator + content = content.replaceAll('aria-label="autoTITLE"', 'aria-label="AUTOTITLE"') + // `{% эндраw %}` / `{% эндраw -%}` — transliterated endraw + content = content.replaceAll('{% эндраw %}', '{% endraw %}') + content = content.replaceAll('{%- эндраw %}', '{%- endraw %}') + content = content.replaceAll('{% эндраw -%}', '{% endraw -%}') + // `{% эндесктоп %}` — transliterated enddesktop + content = content.replaceAll('{% эндесктоп %}', '{% enddesktop %}') + content = content.replaceAll('{%- эндесктоп %}', '{%- enddesktop %}') + // `{% эндекклипс %}` / `{% эндеклипс %}` — transliterated endeclipse + content = content.replaceAll('{% эндеклипс %}', '{% endeclipse %}') + content = content.replaceAll('{%- эндеклипс %}', '{%- endeclipse %}') + content = content.replaceAll('{% эндекклипс %}', '{% endeclipse %}') + // `{% endекклипс %}` — partial transliteration + content = content.replaceAll('{% endекклипс %}', '{% endeclipse %}') + // `{%- лицензия %}` — Russian "license"... actually this is a feature flag value, not a tag + // Translator-formatted "Russian smart quotes" inside Liquid tags: «X» → "X" + content = content.replace(/(\{%-?\s*[a-z]+\s+)«([^»]*)»/g, '$1"$2"') + // `{% ifversion fpt or ghec or ghes >NUMBER %}` — when range value is wrapped in + // Cyrillic chars or letter "о" instead of "0", normalize digits + content = content.replace(/\{%-? (?:ifversion|elsif) [^%]*?[<>=][^%]*?%\}/g, (match) => { + // Cyrillic 'о' (U+043E) often replaces ASCII '0' (U+0030) + return match.replace(/(\d)\s*о/g, '$10').replace(/о\s*(\d)/g, '0$1') + }) + + // Word-order swap: translator placed plan name BEFORE `ifversion`, e.g. + // `{% ghes ifversion %}` → `{% ifversion ghes %}`, + // `{% ghes ifversion < 3,14 %}` → `{% ifversion ghes < 3.14 %}` + content = content.replace( + /\{%(-?)\s*(fpt|ghec|ghes|ghae|ghecom)\s+ifversion\s*([^%]*?)\s*-?%\}/g, + (_m, dash, plan, rest) => { + const fixedRest = rest.replace(/(\d),(\d)/g, '$1.$2') + const trimmed = fixedRest.trim() + return `{%${dash} ifversion ${plan}${trimmed ? ` ${trimmed}` : ''} %}` + }, + ) + // Missing `ifversion` prefix: `{% ghes или ghec %}` → `{% ifversion ghes or ghec %}` + content = content.replace( + /\{%(-?)\s*(fpt|ghec|ghes|ghae|ghecom)\s+или\s+(fpt|ghec|ghes|ghae|ghecom)\s*-?%\}/g, + '{%$1 ifversion $2 or $3 %}', + ) + // Same pattern with "and" / "и" + content = content.replace( + /\{%(-?)\s*(fpt|ghec|ghes|ghae|ghecom)\s+и\s+(fpt|ghec|ghes|ghae|ghecom)\s*-?%\}/g, + '{%$1 ifversion $2 and $3 %}', + ) + // `{% ghes version %}` (translator dropped `ifversion`, added "version") + content = content.replace( + /\{%(-?)\s*(fpt|ghec|ghes|ghae|ghecom)\s+version\s*-?%\}/g, + '{%$1 ifversion $2 %}', + ) + + // Russian "остальных" / "иначе" / "ещё" / "иначе если" → else / elsif + content = content.replaceAll('{% остальных %}', '{% else %}') + content = content.replaceAll('{%- остальных %}', '{%- else %}') + content = content.replaceAll('{% иначе %}', '{% else %}') + content = content.replaceAll('{%- иначе %}', '{%- else %}') + content = content.replaceAll('{% ещё %}', '{% else %}') + content = content.replaceAll('{%- ещё %}', '{%- else %}') + content = content.replace(/\{%(-?)\s*иначе если\s+/g, '{%$1 elsif ') + // Russian `или` = "or", `и` = "and" inside ifversion/elsif/if tags + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?или[^%]*?-?%\}/g, (m) => + m.replace(/\s*или\s*/g, ' or '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\sи\s[^%]*?-?%\}/g, (m) => + m.replace(/\sи\s/g, ' and '), + ) } if (context.code === 'fr') { + // `{% sinon %}` — "otherwise" = else + content = content.replaceAll('{% sinon %}', '{% else %}') + content = content.replaceAll('{%- sinon %}', '{%- else %}') + // `{% référentiel ifversion ` — translator inserted "référentiel" (repository) before ifversion + content = content.replaceAll('{% référentiel ifversion ', '{% ifversion ') + content = content.replaceAll('{%- référentiel ifversion ', '{%- ifversion ') + // Standalone `{% référentiel %}` / `{% paramètres %}` / `{% product %}` are stray + // translation residue with no Liquid meaning — strip them. + content = content.replace(/\{%-?\s*référentiel\s*-?%\}/g, '') + content = content.replace(/\{%-?\s*paramètres\s*-?%\}/g, '') + content = content.replace(/\{%-?\s*product\s*-?%\}/g, '') content = content.replaceAll('{% données variables', '{% data variables') content = content.replaceAll('{% données réutilisables.', '{% data reusables.') content = content.replaceAll('{% variables de données.', '{% data variables.') @@ -567,6 +940,42 @@ export function correctTranslatedContentStrings( content = content.replaceAll('{%- endif %}', '') content = content.replaceAll('{%- endif -%}', '') } + // `{% pour X dans Y %}` — French "for X in Y" + content = content.replace(/\{%(-?)\s*pour\s+(\w+)\s+dans\s+/g, '{%$1 for $2 in ') + // `{% pour le modèle dans Y %}` — "for the model in Y" = `for model in Y` + content = content.replace(/\{%(-?)\s*pour\s+le\s+modèle\s+dans\s+/g, '{%$1 for model in ') + // `{% pour chaque X dans Y %}` — "for each X in Y" = `for X in Y` + content = content.replace(/\{%(-?)\s*pour\s+chaque\s+(\w+)\s+dans\s+/g, '{%$1 for $2 in ') + // `{% des données variables.` — "of the data variables" prefix + content = content.replaceAll('{% des données variables.', '{% data variables.') + content = content.replaceAll('{%- des données variables.', '{%- data variables.') + content = content.replaceAll('{% des data variables.', '{% data variables.') + content = content.replaceAll('{%- des data variables.', '{%- data variables.') + // `{% variables de données.` — already handled via line 484 + // `{% assigner X = Y %}` — "to assign" = assign + content = content.replaceAll('{% assigner ', '{% assign ') + content = content.replaceAll('{%- assigner ', '{%- assign ') + // `{% quand "X" %}` — French "when" inside case/when blocks + content = content.replace(/\{%(-?)\s*quand\s+/g, '{%$1 when ') + // `{% endcase %}` variants + content = content.replaceAll('{% fincas %}', '{% endcase %}') + content = content.replaceAll('{%- fincas %}', '{%- endcase %}') + // `{% réutilisables.X.Y %}` — translated reusables path with no `data` prefix + content = content.replaceAll('{% réutilisables.', '{% data reusables.') + content = content.replaceAll('{%- réutilisables.', '{%- data reusables.') + // Broad fallback: any remaining `{% données ` → `{% data ` (runs LAST so specific + // path-fixing rules above get first crack). + content = content.replace(/\{%(-?)\s*données\s+/g, '{%$1 data ') + // After broad fallback, common translated path segments may remain. + content = content.replace(/\{%(-?\s*)data réutilisables\./g, '{%$1data reusables.') + content = content.replace(/\{%(-?\s*)data variables de\./g, '{%$1data variables.') + // French `ou` = "or", `et` = "and" inside ifversion/elsif/if tags + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\sou\s[^%]*?-?%\}/g, (m) => + m.replace(/\sou\s/g, ' or '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\set\s[^%]*?-?%\}/g, (m) => + m.replace(/\set\s/g, ' and '), + ) } if (context.code === 'ko') { @@ -581,10 +990,44 @@ export function correctTranslatedContentStrings( content = content.replaceAll('{%- 참고 %}', '{%- note %}') content = content.replaceAll('{% 원시 %}', '{% raw %}') content = content.replaceAll('{%- 원시 %}', '{%- raw %}') + // Translated tag name `{% 들여쓰기_데이터_참조 ... %}` → `{% indented_data_reference ... %}` + content = content.replaceAll('{% 들여쓰기_데이터_참조 ', '{% indented_data_reference ') + content = content.replaceAll('{%- 들여쓰기_데이터_참조 ', '{%- indented_data_reference ') + // `{% 옥티콘 "X" ... %}` → `{% octicon "X" ... %}` + content = content.replaceAll('{% 옥티콘 ', '{% octicon ') + content = content.replaceAll('{%- 옥티콘 ', '{%- octicon ') + // `{% 행 머리글 %}` → `{% rowheaders %}` + content = content.replaceAll('{% 행 머리글 %}', '{% rowheaders %}') + content = content.replaceAll('{%- 행 머리글 %}', '{%- rowheaders %}') + content = content.replaceAll('{% 행머리글 %}', '{% rowheaders %}') + content = content.replaceAll('{%- 행머리글 %}', '{%- rowheaders %}') + // `{% 엔드맥 %}` → `{% endmac %}` + content = content.replaceAll('{% 엔드맥 %}', '{% endmac %}') + content = content.replaceAll('{%- 엔드맥 %}', '{%- endmac %}') + // `{% 윈도우즈 %}` / `{% 윈도우 %}` → `{% windows %}` + content = content.replaceAll('{% 윈도우즈 %}', '{% windows %}') + content = content.replaceAll('{%- 윈도우즈 %}', '{%- windows %}') + content = content.replaceAll('{% 윈도우 %}', '{% windows %}') + content = content.replaceAll('{%- 윈도우 %}', '{%- windows %}') + // `{% 데이터 재사용 ` (no period) — variant of `{% data reusables` + content = content.replaceAll('{% 데이터 재사용가능항목.', '{% data reusables.') + content = content.replaceAll('{% 데이터 재사용 가능 항목.', '{% data reusables.') + content = content.replaceAll('{% 데이터 재사용.', '{% data reusables.') + content = content.replaceAll('{% 데이터 재사용 ', '{% data reusables.') + // `{% indented_data_reference 재사용...` — translated `reusables` path prefix + content = content.replace( + /(\{%-?\s*indented_data_reference\s+)재사용(?:\s+가능)?(?:\s+항목)?\./g, + '$1reusables.', + ) // Catch "또는" between any plan names in ifversion/elsif/if tags - content = content.replace(/\{%-? (?:ifversion|elsif|if) [^%]*?또는[^%]*?%\}/g, (match) => { - return match.replace(/ 또는 /g, ' or ') - }) + // (handles `fpt 또는 ghec`, `ghes > 3.15`, etc.) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?또는[^%]*?-?%\}/g, (m) => + m.replace(/\s*또는\s*/g, ' or '), + ) + // Korean "그리고" / "와" / "과" = "and" inside ifversion/elsif/if tags + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?그리고[^%]*?-?%\}/g, (m) => + m.replace(/\s*그리고\s*/g, ' and '), + ) // `{% 그렇지 않으면 %}` — "otherwise" = else content = content.replaceAll('{% 그렇지 않으면 %}', '{% else %}') content = content.replaceAll('{%- 그렇지 않으면 %}', '{%- else %}') @@ -612,6 +1055,39 @@ export function correctTranslatedContentStrings( // `{% 주석 끝 %}` — Korean "주석 끝" (note end) = endnote content = content.replaceAll('{% 주석 끝 %}', '{% endnote %}') content = content.replaceAll('{%- 주석 끝 %}', '{%- endnote %}') + // `{% 데이터.X %}` — translator dropped `variables`/`reusables` + content = content.replaceAll('{% 데이터.variables.', '{% data variables.') + content = content.replaceAll('{% 데이터.reusables.', '{% data reusables.') + // `{% 데이터variables` / `{% 데이터reusables` (no space) + content = content.replaceAll('{% 데이터variables', '{% data variables') + content = content.replaceAll('{% 데이터reusables', '{% data reusables') + content = content.replaceAll('{%- 데이터variables', '{%- data variables') + content = content.replaceAll('{%- 데이터reusables', '{%- data reusables') + // `{% 재사용 가능 항목.` — Korean for "reusables" with no `data` prefix + content = content.replaceAll('{% 재사용 가능 항목.', '{% data reusables.') + content = content.replaceAll('{%- 재사용 가능 항목.', '{%- data reusables.') + // `{% 재사용 가능.` — alternate + content = content.replaceAll('{% 재사용 가능.', '{% data reusables.') + content = content.replaceAll('{%- 재사용 가능.', '{%- data reusables.') + // `{% 데이터 재사용 가능.` / `{% 데이터 재사용 가능 항목.` — full Korean for "data reusables" + content = content.replaceAll('{% 데이터 재사용 가능 항목.', '{% data reusables.') + content = content.replaceAll('{%- 데이터 재사용 가능 항목.', '{%- data reusables.') + content = content.replaceAll('{% 데이터 재사용 가능.', '{% data reusables.') + content = content.replaceAll('{%- 데이터 재사용 가능.', '{%- data reusables.') + // Korean "if" / "elsif" word translations + // `{% 만약 X %}` / `{% 만일 X %}` — "if" in Korean + content = content.replace(/\{%-?\s*만약\s+/g, (m) => + m.startsWith('{%-') ? '{%- if ' : '{% if ', + ) + content = content.replace(/\{%-?\s*만일\s+/g, (m) => + m.startsWith('{%-') ? '{%- if ' : '{% if ', + ) + // Korean "for X in Y" → 위해/대해/안에 patterns + // `{% 위해 X 안에 Y %}` — best-effort for-loop + content = content.replace(/\{%(-?)\s*위해\s+(\w+)\s+안에\s+/g, '{%$1 for $2 in ') + // `{% Variable.` (capital V) — variant + content = content.replaceAll('{% Variable.', '{% data variables.') + content = content.replaceAll('{%- Variable.', '{%- data variables.') } if (context.code === 'de') { @@ -725,10 +1201,234 @@ export function correctTranslatedContentStrings( '{%- ifversion-Sicherheitskampagnen %}', '{%- ifversion security-campaigns %}', ) + // `{% Webseite data variables` / `{%Webseite data variables` — translator inserted + // German "Webseite" (website) before `data variables`. Strip it. + content = content.replaceAll('{%Webseite data variables', '{% data variables') + content = content.replaceAll('{% Webseite data variables', '{% data variables') + content = content.replaceAll('{%- Webseite data variables', '{%- data variables') + // `{% Daten nur variables` — "data only variables" (translator inserted "nur") + content = content.replaceAll('{% Daten nur variables', '{% data variables') + content = content.replaceAll('{%- Daten nur variables', '{%- data variables') + // `{% Dateneinstellungen variables` — "data settings variables" (compound) = data + content = content.replaceAll('{% Dateneinstellungen variables', '{% data variables') + content = content.replaceAll('{%- Dateneinstellungen variables', '{%- data variables') + // `{% Datenpaket variables` — "data package variables" (compound) = data + content = content.replaceAll('{% Datenpaket variables', '{% data variables') + content = content.replaceAll('{%- Datenpaket variables', '{%- data variables') + // `{% datan variables` — typo of "Daten" + content = content.replaceAll('{% datan variables', '{% data variables') + content = content.replaceAll('{%- datan variables', '{%- data variables') + // `{%-Daten-variables` and `{%-Datenvariablen` (no space) handled at line 647-648 + // Add the `{%-Datenvariablen.` no-space variant + content = content.replaceAll('{%-Datenvariablen.', '{%- data variables.') + // Broad fallback: any remaining `{% Daten ` / `{% daten ` → `{% data ` + // Runs LAST so specific path-fixing rules above get first crack. + content = content.replace(/\{%(-?)\s*[Dd]aten\s+/g, '{%$1 data ') + // After broad fallback, translated path segments may remain in `{% data X.Y %}` + // where X is German. Catch the most common: `wiederverwendbar.` → `reusables.` + content = content.replace( + /\{%(-?\s*)data wiederverwendbar(?:e|en|ens)?\./g, + '{%$1data reusables.', + ) + content = content.replace(/\{%(-?\s*)data Variablen\./g, '{%$1data variables.') + // German `oder` = "or", `und` = "and" inside ifversion/elsif/if tags + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\soder\s[^%]*?-?%\}/g, (m) => + m.replace(/\soder\s/g, ' or '), + ) + content = content.replace(/\{%-?\s+(?:ifversion|elsif|if)\s+[^%]*?\sund\s[^%]*?-?%\}/g, (m) => + m.replace(/\sund\s/g, ' and '), + ) + // Translated tag name `{% eingerucktes_datenverweis ... %}` → `{% indented_data_reference ... %}` + content = content.replaceAll('{% eingerucktes_datenverweis ', '{% indented_data_reference ') + content = content.replaceAll('{%- eingerucktes_datenverweis ', '{%- indented_data_reference ') } // --- Generic fixes (all languages) --- + // Inside ANY Liquid tag `{% ... %}` (including `{% octicon ... %}`, + // `{% data ... %}`, `{% assign ... %}` etc.), normalize typographic + // quotation marks back to ASCII straight quotes. Translators + // frequently smart-quote attribute values, which breaks the parser. + // Handles: « » (guillemets, fr/ru/es/it), “ ” (CJK double quotes, + // U+201C/U+201D, used in zh/ko/ja), „ “ ‚ ‘ (German low-9/high-6 + // quotes, U+201E/U+201C/U+201A/U+2018) and ' ' (curly singles). + content = content.replace(/\{%-?[^%]*?-?%\}/g, (match) => { + return match.replace(/[«»“”„]/g, '"').replace(/[‘’‚]/g, "'") + }) + + // Inside `{% ifversion|elsif|if ... %}` collapse runs of internal whitespace + // to a single space. Translators occasionally introduce double spaces + // (e.g. `{% ifversion fpt or ghec %}`), and although a single trailing + // space is fine, some patterns trip the parser. Safe to apply globally. + content = content.replace( + /\{%(-?)\s+(ifversion|elsif|if)\s+([^%]*?)\s*(-?)%\}/g, + (_m, dashOpen, tag, body, dashClose) => + `{%${dashOpen} ${tag} ${body.replace(/\s+/g, ' ').trim()} ${dashClose}%}`, + ) + + // Octicon icon-name English-content recovery. Translators often translate + // the icon name itself (e.g. `{% octicon "карандаш" %}` for "pencil"). The + // Octicon parser will then either fail with "Octicon X does not exist" or + // — because its regex is not anchored — match a later quoted attribute value + // such as `aria-hidden="true"` and report "Octicon true does not exist". + // Recover the original icon name by position when the english content is + // available and contains the same number of `{% octicon "" ... %}` + // tags as the translation. + if (englishContent && content.includes('{% octicon ')) { + const englishNames: string[] = [] + for (const m of englishContent.matchAll(/\{%-?\s*octicon\s+"([^"]*)"/g)) { + englishNames.push(m[1]) + } + // Count translated octicon tags (whether or not they have a quoted name). + const translatedAll = [...content.matchAll(/\{%-?\s*octicon\b[^%]*%\}/g)] + const translatedMatches = [...content.matchAll(/\{%-?\s*octicon\s+"([^"]*)"/g)] + if ( + englishNames.length > 0 && + translatedMatches.length === englishNames.length && + translatedMatches.some((m, i) => m[1] !== englishNames[i]) + ) { + let i = 0 + content = content.replace( + /(\{%-?\s*octicon\s+")([^"]*)(")/g, + (_match, prefix, _name, suffix) => { + const englishName = englishNames[i++] + return `${prefix}${englishName}${suffix}` + }, + ) + } else if (englishNames.length > 0) { + // Counts differ. Replace any non-ASCII icon name with a positional + // English fallback (clamped to valid range). Real octicon names are + // always ASCII, so non-ASCII is always wrong. + let i = 0 + content = content.replace( + /(\{%-?\s*octicon\s+")([^"]*)(")/g, + (match, prefix, name, suffix) => { + // eslint-disable-next-line no-control-regex + if (/[^\x00-\x7F]/.test(name)) { + const englishName = englishNames[Math.min(i, englishNames.length - 1)] + i++ + return `${prefix}${englishName}${suffix}` + } + i++ + return match + }, + ) + } + + // Translators sometimes drop the `"name"` first argument entirely: + // `{% octicon aria-label="..." %}` instead of `{% octicon "copy" aria-label="..." %}`. + // When tag counts match the English version, recover by injecting the + // positional English icon name. + if (englishNames.length > 0 && translatedAll.length === englishNames.length) { + let i = 0 + content = content.replace( + /(\{%-?\s*octicon)(\s+)([^"%][^%]*?)(\s*-?%\})/g, + (_m, head, ws, body, tail) => { + const name = englishNames[i++] + return `${head}${ws}"${name}" ${body.trim()} ${tail.trimStart()}` + }, + ) + } + } + + // After octicon recovery, the surrounding `{% octicon "X" ... %}` may still + // contain translated `aria-label` values. That's OK — Liquid parses key=value + // tokens regardless of non-ASCII content in the value. + + // `{% indented_data_reference spaces=N %}` recovery. Translators + // sometimes translate the reusables path (e.g. `재사용.X.Y` for ko, + // `wiederverwendbar.X.Y` for de) or insert internal spaces (ru: + // `повторно используемых пространств.X.Y`), which breaks the parser + // ("'spaces=NUMBER' must include a number"). Recover by replacing the + // entire path positionally from the English version when counts match. + if (englishContent && content.includes('{% indented_data_reference ')) { + const englishArgs: string[] = [] + for (const m of englishContent.matchAll( + /\{%-?\s*indented_data_reference\s+([^%]*?)\s*-?%\}/g, + )) { + englishArgs.push(m[1].trim()) + } + const translatedMatches = [ + ...content.matchAll(/\{%-?\s*indented_data_reference\s+([^%]*?)\s*-?%\}/g), + ] + if ( + englishArgs.length > 0 && + translatedMatches.length === englishArgs.length && + translatedMatches.some((m, i) => m[1].trim() !== englishArgs[i]) + ) { + let i = 0 + content = content.replace( + /(\{%-?\s*indented_data_reference\s+)([^%]*?)(\s*-?%\})/g, + (_match, prefix, _args, suffix) => { + const englishArg = englishArgs[i++] + return `${prefix}${englishArg}${suffix}` + }, + ) + } else if (englishArgs.length > 0) { + // Counts differ. Replace any args containing non-ASCII characters with + // the positional English fallback (clamped). Valid args are always ASCII. + let i = 0 + content = content.replace( + /(\{%-?\s*indented_data_reference\s+)([^%]*?)(\s*-?%\})/g, + (match, prefix, args, suffix) => { + // eslint-disable-next-line no-control-regex + if (/[^\x00-\x7F]/.test(args)) { + const englishArg = englishArgs[Math.min(i, englishArgs.length - 1)] + i++ + return `${prefix}${englishArg}${suffix}` + } + i++ + return match + }, + ) + } + } + + // `{% data %}` recovery. Translators sometimes translate the path + // segments (e.g. `数据.可重用.X.Y` for zh, `재사용 가능.X.Y` for ko, + // `wiederverwendbar.X.Y` for de). When the data tag itself parses but the + // resolved path doesn't exist, we get "Can't find the key 'X' in the scope". + // Recover by replacing the entire path positionally from the English version + // when counts match, or by swapping any path containing non-ASCII characters + // with the positional English fallback. Valid `{% data %}` paths are always + // ASCII (lowercase letters, digits, dots, underscores, hyphens). + if (englishContent && content.includes('{% data ')) { + const englishArgs: string[] = [] + for (const m of englishContent.matchAll(/\{%-?\s*data\s+([^%]*?)\s*-?%\}/g)) { + englishArgs.push(m[1].trim()) + } + const translatedMatches = [...content.matchAll(/\{%-?\s*data\s+([^%]*?)\s*-?%\}/g)] + if ( + englishArgs.length > 0 && + translatedMatches.length === englishArgs.length && + translatedMatches.some((m, i) => m[1].trim() !== englishArgs[i]) + ) { + let i = 0 + content = content.replace( + /(\{%-?\s*data\s+)([^%]*?)(\s*-?%\})/g, + (_match, prefix, _args, suffix) => { + const englishArg = englishArgs[i++] + return `${prefix}${englishArg}${suffix}` + }, + ) + } else if (englishArgs.length > 0) { + let i = 0 + content = content.replace( + /(\{%-?\s*data\s+)([^%]*?)(\s*-?%\})/g, + (match, prefix, args, suffix) => { + // eslint-disable-next-line no-control-regex + if (/[^\x00-\x7F]/.test(args)) { + const englishArg = englishArgs[Math.min(i, englishArgs.length - 1)] + i++ + return `${prefix}${englishArg}${suffix}` + } + i++ + return match + }, + ) + } + } + // Strip leaked LLM sentinel markers (e.g. `<|endoftext|>`) that // occasionally survive the translation pipeline. Replace the marker // and any surrounding whitespace with a single space so adjacent @@ -957,5 +1657,108 @@ export function correctTranslatedContentStrings( content = content.replaceAll('{%endraw %}', '{% endraw %}') content = content.replaceAll('{%endraw -%}', '{% endraw -%}') + // Strip stray closing-only Liquid tags that have no matching opener anywhere + // in the content. Translators sometimes insert spurious closers (e.g. an + // extra `{% endif %}`) when they re-arrange paragraphs. We only remove a + // stray closer when there are strictly more closers than possible openers, + // and we remove from the END of the content first (most likely the stray). + // + // We treat each closer with its set of valid opener regexes: + // endif ← `{% if `, `{% ifversion ` + // endfor ← `{% for ` + // endraw ← `{% raw %}` + // endcase ← `{% case ` + // endcomment ← `{% comment %}` + // endcapture ← `{% capture ` + // endnote ← `{% note %}` + // endwarning ← `{% warning %}` + // endtip ← `{% tip %}` + // endcaution ← `{% caution %}` + // endimportant← `{% important %}` + // endrowheaders← `{% rowheaders %}` + // enddesktop ← `{% desktop %}` + // endmac ← `{% mac %}` + // endwebui ← `{% webui %}` + // endwindowsterminal ← `{% windowsterminal %}` + // endwindows ← `{% windows %}` + // endlinux ← `{% linux %}` + // endeclipse ← `{% eclipse %}` + // endjetbrains← `{% jetbrains %}` + // endvscode ← `{% vscode %}` + // endvisualstudio ← `{% visualstudio %}` + // endprompt ← `{% prompt %}` + // endmobile ← `{% mobile %}` + // endcli ← `{% cli %}` + // endcurl ← `{% curl %}` + // endindented_data_reference ← `{% indented_data_reference ` + // + // `else` / `elsif` are stripped only when no `if`/`ifversion` opener exists. + const closerToOpeners: Array<[string, RegExp]> = [ + ['endif', /\{%-?\s*(?:if|ifversion)\s/], + ['endfor', /\{%-?\s*for\s/], + ['endraw', /\{%-?\s*raw\s*-?%\}/], + ['endcase', /\{%-?\s*case\s/], + ['endcomment', /\{%-?\s*comment\s*-?%\}/], + ['endcapture', /\{%-?\s*capture\s/], + ['endnote', /\{%-?\s*note\s*-?%\}/], + ['endwarning', /\{%-?\s*warning\s*-?%\}/], + ['endtip', /\{%-?\s*tip\s*-?%\}/], + ['endcaution', /\{%-?\s*caution\s*-?%\}/], + ['endimportant', /\{%-?\s*important\s*-?%\}/], + ['endrowheaders', /\{%-?\s*rowheaders\s*-?%\}/], + ['enddesktop', /\{%-?\s*desktop\s*-?%\}/], + ['endmac', /\{%-?\s*mac\s*-?%\}/], + ['endwebui', /\{%-?\s*webui\s*-?%\}/], + ['endwindowsterminal', /\{%-?\s*windowsterminal\s*-?%\}/], + ['endwindows', /\{%-?\s*windows\s*-?%\}/], + ['endlinux', /\{%-?\s*linux\s*-?%\}/], + ['endeclipse', /\{%-?\s*eclipse\s*-?%\}/], + ['endjetbrains', /\{%-?\s*jetbrains\s*-?%\}/], + ['endvscode', /\{%-?\s*vscode\s*-?%\}/], + ['endvisualstudio', /\{%-?\s*visualstudio\s*-?%\}/], + ['endprompt', /\{%-?\s*prompt\s*-?%\}/], + ['endmobile', /\{%-?\s*mobile\s*-?%\}/], + ['endcli', /\{%-?\s*cli\s*-?%\}/], + ['endcurl', /\{%-?\s*curl\s*-?%\}/], + ['endindented_data_reference', /\{%-?\s*indented_data_reference\s/], + ] + + // Tests that exercise individual transformations in isolation can opt out + // of the orphan-closer stripping below (which is tested separately). + if (context.skipOrphanStripping) { + return content + } + + for (const [closer, openerRegex] of closerToOpeners) { + const closerRegex = new RegExp(`\\{%-?\\s*${closer}\\s*-?%\\}`, 'g') + const closers = content.match(closerRegex) + if (!closers) continue + // Count openers using a global version of the opener regex. + const globalOpener = new RegExp(openerRegex.source, `${openerRegex.flags}g`) + const openers = content.match(globalOpener) + const openerCount = openers ? openers.length : 0 + const closerCount = closers.length + if (closerCount <= openerCount) continue + // Remove (closerCount - openerCount) closers, starting from the LAST. + let toRemove = closerCount - openerCount + const positions: Array<{ start: number; end: number }> = [] + closerRegex.lastIndex = 0 + let m: RegExpExecArray | null + while ((m = closerRegex.exec(content)) !== null) { + positions.push({ start: m.index, end: m.index + m[0].length }) + } + // Remove from the END (translator-appended extras). + for (let i = positions.length - 1; i >= 0 && toRemove > 0; i--, toRemove--) { + const { start, end } = positions[i] + content = content.slice(0, start) + content.slice(end) + } + } + + // Strip stray `else` / `elsif` when no `if`/`ifversion` exists at all. + if (!/\{%-?\s*(?:if|ifversion)\s/.test(content)) { + content = content.replace(/\{%-?\s*else\s*-?%\}/g, '') + content = content.replace(/\{%-?\s*elsif\s+[^%]*?-?%\}/g, '') + } + return content } diff --git a/src/languages/tests/correct-translation-content.ts b/src/languages/tests/correct-translation-content.ts index 26f5382ff528..fb657cea1273 100644 --- a/src/languages/tests/correct-translation-content.ts +++ b/src/languages/tests/correct-translation-content.ts @@ -7,6 +7,7 @@ function fix(content: string, code: string, englishContent = '') { return correctTranslatedContentStrings(content, englishContent, { code, relativePath: 'test.md', + skipOrphanStripping: true, }) } @@ -781,11 +782,13 @@ describe('correctTranslatedContentStrings', () => { test('removes orphaned endif when no matching ifversion/elsif opener exists', () => { // Caused by translations where only the closing tag survived (e.g. user-api.md reusable) - expect(fix('Some content\n{% endif %}\nMore content', 'fr')).toBe( + const fixWithStrip = (s: string) => + correctTranslatedContentStrings(s, '', { code: 'fr', relativePath: 'test.md' }) + expect(fixWithStrip('Some content\n{% endif %}\nMore content')).toBe( 'Some content\n\nMore content', ) - expect(fix('Line one\n{%- endif %}\nLine two', 'fr')).toBe('Line one\n\nLine two') - expect(fix('Text {%- endif -%} more', 'fr')).toBe('Text more') + expect(fixWithStrip('Line one\n{%- endif %}\nLine two')).toBe('Line one\n\nLine two') + expect(fixWithStrip('Text {%- endif -%} more')).toBe('Text more') }) test('preserves endif when matching ifversion opener is present', () => { @@ -1464,6 +1467,33 @@ describe('correctTranslatedContentStrings', () => { expect(fix('{{%raw %}', 'es')).toBe('{% raw %}') expect(fix('{{% raw %}', 'es')).toBe('{% raw %}') }) + + test('rejoins broken bullet markers split across lines (all languages)', () => { + // Lone `*` with content on indented next line → `* content` + const broken = '* \n [AUTOTITLE](/orgs/transfer)' + const expected = '* [AUTOTITLE](/orgs/transfer)' + for (const lang of ['ja', 'de', 'es', 'fr', 'ko', 'pt', 'ru', 'zh']) { + expect(fix(broken, lang)).toBe(expected) + } + // No trailing space variant + expect(fix('*\n [AUTOTITLE](/path)', 'ko')).toBe('* [AUTOTITLE](/path)') + // Multiple consecutive broken bullets + expect(fix('* \n one\n* \n two', 'fr')).toBe('* one\n* two') + // Valid bullets are not modified + expect(fix('* normal\n* another', 'de')).toBe('* normal\n* another') + }) + + test('rejoins broken table cells split across lines (all languages)', () => { + const broken = '|\n **クラウドとサーバー** | 説明' + const expected = '| **クラウドとサーバー** | 説明' + for (const lang of ['ja', 'de', 'es', 'fr', 'ko', 'pt', 'ru', 'zh']) { + expect(fix(broken, lang)).toBe(expected) + } + // Pipe with trailing whitespace + expect(fix('| \n cell text', 'zh')).toBe('| cell text') + // Valid table rows are not modified + expect(fix('| a | b |\n| c | d |', 'es')).toBe('| a | b |\n| c | d |') + }) }) // ─── EDGE CASES ────────────────────────────────────────────────────