diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e73182c6238b..30f6ce6a2427 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -60,7 +60,7 @@ // Lifecycle commands // Install dependencies then install Copilot CLI - "onCreateCommand": "npm ci && npm config set \"//npm.pkg.github.com/:_authToken=$GITHUB_TOKEN\" && npm config set \"@github:registry=https://npm.pkg.github.com/\" && npm install -g @github/copilot", + "onCreateCommand": "npm ci && npm install -g @github/copilot@prerelease", // Start a web server and keep it running "postStartCommand": "nohup bash -c 'npm start &'", // Set port 4000 to be public diff --git a/.github/workflows/generate-code-scanning-query-lists.yml b/.github/workflows/generate-code-scanning-query-lists.yml index 200b5b3527db..a3e261803b87 100644 --- a/.github/workflows/generate-code-scanning-query-lists.yml +++ b/.github/workflows/generate-code-scanning-query-lists.yml @@ -153,8 +153,10 @@ jobs: --title "Update CodeQL query tables" \ --repo github/docs-internal \ --label "codeql-query-tables,skip FR board,ready-for-doc-review,workflow-generated" \ - --body '👋 humans. This PR updates the **CodeQL query table reusables** with the latest changes in preparation for the next **CodeQL CLI** release. + --body '👋 humans. This PR updates the **CodeQL query table reusables** with the latest changes in preparation for the next **CodeQL CLI** release. (Synced from codeql@${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }}) - No action is required from the first responder for the Docs content team. This PR will be reviewed and merged by the Code scanning and GHAS focus team as part of the next release of CodeQL CLI. (Synced from codeql@${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }}) - If CI does not pass or other problems arise, contact #docs-engineering on slack.' + No action is required from the first responder for the Docs content team. This PR is automatically added to the Docs content review board. Any writer can review this by checking that the PR looks sensible. If CI does not pass or other problems arise, contact #docs-engineering on slack. + + + When the DRI for the CodeQL CLI release is ready to publish, they will ask us to merge this PR in #docs-content.' diff --git a/content/actions/reference/runners/self-hosted-runners.md b/content/actions/reference/runners/self-hosted-runners.md index 8924b2df2c9e..b58315eb0a25 100644 --- a/content/actions/reference/runners/self-hosted-runners.md +++ b/content/actions/reference/runners/self-hosted-runners.md @@ -121,7 +121,7 @@ If you disable automatic updates, you will be required to update your runner ver For instructions on how to install the latest runner version, see the installation instructions for [the latest release](https://github.com/actions/runner/releases). ->[!WARNING] Any updates released for the software, including major, minor or patch releases, are considered as an available update. If you do not perform a software update within 30 days, the {% data variables.product.prodname_actions %} service will not queue jobs to your runner. In addition, if a critical security update is required, the {% data variables.product.prodname_actions %} service will not queue jobs to your runner until it has been updated. +{% data reusables.actions.self-hosted-runner-update-warning %} ### Webhooks for autoscaling diff --git a/content/actions/tutorials/use-actions-runner-controller/troubleshoot.md b/content/actions/tutorials/use-actions-runner-controller/troubleshoot.md index 26d7a69612ad..c962e7735126 100644 --- a/content/actions/tutorials/use-actions-runner-controller/troubleshoot.md +++ b/content/actions/tutorials/use-actions-runner-controller/troubleshoot.md @@ -157,6 +157,14 @@ A `401 Unauthorized` error when attempting to obtain an access token for a {% da {% data reusables.actions.self-hosted-runner-group-limit %} +## Runner updates + +{% data reusables.actions.self-hosted-runner-update-warning %} + +Validate that your runner software version and/or custom runner image(s) in use are running the latest version. + +For more information, see [AUTOTITLE](/actions/reference/runners/self-hosted-runners). + ## Legal notice {% data reusables.actions.actions-runner-controller-legal-notice %} diff --git a/content/copilot/how-tos/use-copilot-for-common-tasks/use-copilot-to-create-issues.md b/content/copilot/how-tos/use-copilot-for-common-tasks/use-copilot-to-create-issues.md index cffb47c3d942..54d61a4c8459 100644 --- a/content/copilot/how-tos/use-copilot-for-common-tasks/use-copilot-to-create-issues.md +++ b/content/copilot/how-tos/use-copilot-for-common-tasks/use-copilot-to-create-issues.md @@ -37,6 +37,7 @@ You can create issues from {% data variables.copilot.copilot_chat_short %}'s imm * {% prompt %}In OWNER/REPOSITORY, create a feature request to add fuzzy matching to search.{% endprompt %} * {% prompt %}Log a bug for a 500 error. This happens consistently when I try to log into the site.{% endprompt %} * {% prompt %}Create a task to change the application logo background to red and add the label "needs design review".{% endprompt %} + * {% prompt %}In octo-org/octo-repo, create an issue and add relevant code snippets to improve the API response format.{% endprompt %} > [!NOTE] You can only use {% data variables.product.prodname_copilot_short %} to create issues in repositories where you already have permission to create issues. This feature doesn't change your access or bypass repository permissions. diff --git a/content/copilot/tutorials/copilot-chat-cookbook/document-code/creating-issues.md b/content/copilot/tutorials/copilot-chat-cookbook/document-code/creating-issues.md new file mode 100644 index 000000000000..f2bcbb49e0c5 --- /dev/null +++ b/content/copilot/tutorials/copilot-chat-cookbook/document-code/creating-issues.md @@ -0,0 +1,80 @@ +--- +title: Creating issues +shortTitle: Create issues +intro: '{% data variables.copilot.copilot_chat_short %} can help you quickly create issues without filling out every field manually.' +versions: + feature: copilot +complexity: + - Simple +octicon: copilot +category: + - Document code +topics: + - Copilot +contentType: tutorials +--- + +Creating issues manually can be time-consuming. {% data variables.copilot.copilot_chat_short %} lets you create issues from natural language, and automatically fills in the title, body, labels, and other metadata based on your prompt. + +## Example scenario + +You're working on an API service and need to add server-side validation to the `createUser` endpoint. Instead of drafting the issue manually, you use {% data variables.copilot.copilot_chat_short %} to generate a detailed issue description that includes an example implementation of the validation middleware. + +The following snippet shows the current implementation of the `createUser` route, before validation is added: + +```javascript +// Route +app.post('/users', validateCreateUser, (req, res) => { + const { username, email } = req.body; + // Simulate user creation + res.status(201).json({ message: 'User created', user: { username, email } }); +}); +``` + +## Example prompt + +`In octo-org/octo-repo, create an issue to add server-side validation for the createUser API endpoint. Include an example of how to validate the request body using an existing middleware pattern. Label it with "backend" and "enhancement".` + +## Example response + +{% data reusables.copilot.example-prompts.response-is-an-example %} + +When you submit the prompt, {% data variables.copilot.copilot_chat_short %} generates a draft issue based on your description and includes a code snippet. You can review and edit the draft before creating the issue. + +```markdown +## Problem +The `createUser` API endpoint currently lacks robust server-side validation for incoming requests. To ensure data integrity and security, we should validate the request body before proceeding with user creation. + +**Current API endpoint:** +// Route +app.post('/users', validateCreateUser, (req, res) => { + const { username, email } = req.body; + // Simulate user creation + res.status(201).json({ message: 'User created', user: { username, email } }); +}); + +## Proposal +- Add server-side validation for the request body using the existing middleware pattern. +- Ensure required fields (`username`, `email`) are present and valid. +- Return a 400 Bad Request response if validation fails. + +**Example (middleware pattern):** +function validateCreateUser(req, res, next) { + const { username, email } = req.body; + if (!username || !email) { + return res.status(400).json({ error: 'Username and email are required.' }); + } + // Additional validation logic here + next(); +} + +app.post('/users', validateCreateUser, (req, res) => { + // ... +}); + + +## Acceptance Criteria +- Server-side validation middleware is added to the `createUser` endpoint. +- Request body is properly validated. +- Appropriate error responses are returned for invalid requests. +``` diff --git a/content/copilot/tutorials/copilot-chat-cookbook/document-code/index.md b/content/copilot/tutorials/copilot-chat-cookbook/document-code/index.md index ae6fd10d4160..000be617833b 100644 --- a/content/copilot/tutorials/copilot-chat-cookbook/document-code/index.md +++ b/content/copilot/tutorials/copilot-chat-cookbook/document-code/index.md @@ -10,6 +10,7 @@ versions: topics: - Copilot children: + - /creating-issues - /document-legacy-code - /explain-legacy-code - /explain-complex-logic diff --git a/content/copilot/tutorials/plan-a-project.md b/content/copilot/tutorials/plan-a-project.md index 2366589e5a84..618660fbb759 100644 --- a/content/copilot/tutorials/plan-a-project.md +++ b/content/copilot/tutorials/plan-a-project.md @@ -88,12 +88,12 @@ After you finish generating the issue tree you may notice that {% data variables 1. Start with the newly generated issue such as "Task: Create placeholder pages for main routes". Prompt {% data variables.product.prodname_copilot_short %} with: - ```Can you improve the description for “Task: Create placeholder pages for main routes”? Please provide a detailed technical summary, list the main routes to be included, outline the steps for implementation, and specify what should be delivered for this task.``` + ```Can you improve the description for “Task: Create placeholder pages for main routes”? Please provide a detailed technical summary, list the main routes to be included, outline the steps for implementation, and specify what should be delivered for this task. Please add any relevant code snippets.``` 1. {% data variables.product.prodname_copilot_short %} will generate a new version of the draft issue "Task: Create placeholder pages for main routes." At the top-left of the issue, click the versioning drop-down and select **Version 2** to review the new changes. -1. Review and decide whether to keep {% data variables.product.prodname_copilot_short %}’s revised version, edit further, or prompt again for more detail. +1. Review and decide whether to keep {% data variables.product.prodname_copilot_short %}’s revised version, edit further, or prompt again for more detail. {% data variables.product.prodname_copilot_short %} can add code snippets into the draft to improve clarity and provide immediate context for these issues. 1. Repeat this process for other issues in the epic, refining descriptions and breaking down tasks as needed. 1. Once you’re satisfied with the issue descriptions, click **Create all** to create the issues in your repository. diff --git a/data/reusables/actions/self-hosted-runner-update-warning.md b/data/reusables/actions/self-hosted-runner-update-warning.md new file mode 100644 index 000000000000..a9b3a40c9294 --- /dev/null +++ b/data/reusables/actions/self-hosted-runner-update-warning.md @@ -0,0 +1 @@ +>[!WARNING] Any updates released for the software, including major, minor, or patch releases, are considered as an available update. If you do not perform a software update within 30 days, the {% data variables.product.prodname_actions %} service will not queue jobs to your runner. In addition, if a critical security update is required, the {% data variables.product.prodname_actions %} service will not queue jobs to your runner until it has been updated. diff --git a/src/frame/components/UtmPreserver.tsx b/src/frame/components/UtmPreserver.tsx new file mode 100644 index 000000000000..34e79445e7e1 --- /dev/null +++ b/src/frame/components/UtmPreserver.tsx @@ -0,0 +1,106 @@ +import { useEffect } from 'react' +import { useRouter } from 'next/router' + +type UtmPreserverProps = { + // CSS selector for links that should preserve UTM parameters + linkSelector?: string + // Specific page paths where this component should be active + activePaths?: string[] +} + +export const UtmPreserver = ({ + linkSelector = 'a[href*="github.com/copilot"], a[href*="github.com/github-copilot"]', + activePaths = ['/copilot/get-started/plans'], +}: UtmPreserverProps) => { + const router = useRouter() + + useEffect(() => { + // Check if current page should have UTM preservation + const shouldPreserveUtm = activePaths.some((path) => router.asPath.includes(path)) + if (!shouldPreserveUtm) return + + // Extract UTM parameters from current URL + const getUtmParams = (): URLSearchParams => { + const urlParams = new URLSearchParams(window.location.search) + const utmParams = new URLSearchParams() + + for (const [key, value] of urlParams) { + if (key.startsWith('utm_')) { + utmParams.set(key, value) + } + } + + return utmParams + } + + // Add UTM parameters to a URL + const addUtmParamsToUrl = (url: string, utmParams: URLSearchParams): string => { + try { + const urlObj = new URL(url) + + for (const [key, value] of utmParams) { + urlObj.searchParams.set(key, value) + } + + return urlObj.toString() + } catch { + // If URL parsing fails, return original URL + return url + } + } + + // Apply UTM parameters to relevant links + const applyUtmToLinks = (): void => { + const utmParams = getUtmParams() + + if (utmParams.toString() === '') return + + const links = document.querySelectorAll(linkSelector) + + links.forEach((link) => { + if (link.href && (link.href.startsWith('http://') || link.href.startsWith('https://'))) { + link.href = addUtmParamsToUrl(link.href, utmParams) + } + }) + } + + // Handle click events for dynamic link modification + const handleLinkClick = (event: Event): void => { + const link = (event.target as Element)?.closest('a') as HTMLAnchorElement + if (!link) return + + // Check if this link matches our selector + if (!link.matches(linkSelector)) return + + const utmParams = getUtmParams() + if (utmParams.toString() === '') return + + if (link.href && (link.href.startsWith('http://') || link.href.startsWith('https://'))) { + link.href = addUtmParamsToUrl(link.href, utmParams) + } + } + + // Apply UTM parameters immediately to existing links + applyUtmToLinks() + + // Also handle clicks for any dynamically added links + document.addEventListener('click', handleLinkClick, true) + + // Re-apply when the route changes (for single-page navigation) + const handleRouteChange = () => { + // Small delay to ensure DOM has updated + setTimeout(applyUtmToLinks, 100) + } + + router.events.on('routeChangeComplete', handleRouteChange) + + // Cleanup + return () => { + document.removeEventListener('click', handleLinkClick, true) + router.events.off('routeChangeComplete', handleRouteChange) + } + }, [router.asPath, router.events, linkSelector, activePaths]) + + // This component doesn't render anything + return null +} diff --git a/src/frame/components/article/ArticlePage.tsx b/src/frame/components/article/ArticlePage.tsx index 882edee0003d..89ef49ed8842 100644 --- a/src/frame/components/article/ArticlePage.tsx +++ b/src/frame/components/article/ArticlePage.tsx @@ -21,6 +21,7 @@ import { Breadcrumbs } from '@/frame/components/page-header/Breadcrumbs' import { Link } from '@/frame/components/Link' import { useTranslation } from '@/languages/components/useTranslation' import { LinkPreviewPopover } from '@/links/components/LinkPreviewPopover' +import { UtmPreserver } from '@/frame/components/UtmPreserver' const ClientSideRefresh = dynamic(() => import('@/frame/components/ClientSideRefresh'), { ssr: false, @@ -101,6 +102,7 @@ export const ArticlePage = () => { return ( + {isDev && } {router.pathname.includes('/rest/') && } {currentLayout === 'inline' ? (