diff --git a/.agents/skills/triage/comment.md b/.agents/skills/triage/comment.md index 36c3c6d4a3c6..ecbf304e7a20 100644 --- a/.agents/skills/triage/comment.md +++ b/.agents/skills/triage/comment.md @@ -38,7 +38,7 @@ Generate and return a GitHub comment following the template below. ```markdown **[I was able to reproduce this issue. / I was unable to reproduce this issue.]** [1-2 sentences describing the result and key observations.] -**Fix:** [If `branchName` arg is non-null, include: [Create PR](https://github.com/withastro/astro/compare/{branchName}?expand=1)] **[I was able to fix this issue. / I was unable to fix this issue]** [1-2 sentences describing the solution and key observations. Even if no fix was created, you can still use this space to give guidance or "a best guess" at where the fix might be.] +**Fix:** **[I was able to fix this issue. / I was unable to fix this issue]** [1-2 sentences describing the solution and key observations. Even if no fix was created, you can still use this space to give guidance or "a best guess" at where the fix might be.] [If `branchName` arg is non-null, include this link: [View Fix](https://github.com/withastro/astro/compare/{branchName}?expand=1)] **Cause:** [Single sentence explaining the root cause - or just the word "Unknown" if not determined.] diff --git a/.changeset/ripe-nights-feel.md b/.changeset/ripe-nights-feel.md index 05b9147a57c4..76166eb32791 100644 --- a/.changeset/ripe-nights-feel.md +++ b/.changeset/ripe-nights-feel.md @@ -2,16 +2,10 @@ 'astro': minor --- -Responsive images are now supported when `security.csp` is enabled, out of the box. +Adds support for responsive images when `security.csp` is enabled, out of the box. -Before, the styles for responsive images were injected using the `style="""` attribute, and the image would look like this: +Astro's implementation of responsive image styles has been updated to be compatible with a configured Content Security Policy. -```html - -``` +Instead of, injecting style elements at runtime, Astro will now generate your styles at build time using a combination of `class=""` and `data-*` attributes. This means that your processed styles are loaded and hashed out of the box by Astro. -After this change, styles now use a combination of `class=""` and data attributes. The image would look like this: - -```html - -``` +If you were previously choosing between Astro's CSP feature and including responsive images on your site, you may now use them together. diff --git a/.changeset/short-pears-hammer.md b/.changeset/short-pears-hammer.md new file mode 100644 index 000000000000..42a18f562a36 --- /dev/null +++ b/.changeset/short-pears-hammer.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes a case where setting `vite.server.allowedHosts: true` was turned into an invalid array diff --git a/.flue/workflows/issue-triage.ts b/.flue/workflows/issue-triage.ts index e7e190bba520..068e24688bb9 100644 --- a/.flue/workflows/issue-triage.ts +++ b/.flue/workflows/issue-triage.ts @@ -31,6 +31,21 @@ const fixResultSchema = v.object({ ), }); +const labelResultSchema = v.object({ + priority: v.pipe( + v.nullable(v.string()), + v.description( + 'Exactly one priority label name (e.g. "P4: important"), or null if unable to determine priority', + ), + ), + packages: v.pipe( + v.array(v.string()), + v.description( + 'One or more package label names (e.g. ["pkg: astro", "pkg: react"]). Empty array if unable to determine package.', + ), + ), +}); + export default async function triage(flue: Flue) { const { issueNumber } = flue.args as { issueNumber: number; @@ -135,6 +150,66 @@ Return only "yes" or "no" inside the ---RESULT_START--- / ---RESULT_END--- block await flue.shell(`gh issue edit ${issueNumber} --remove-label "needs triage"`, { env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN }, }); + + // Fetch all repo labels and select appropriate priority + package labels. + const labelsJson = await flue.shell( + "gh api repos/withastro/astro/labels --paginate --jq '.[] | {name, description}'", + { env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN } }, + ); + const allLabels = labelsJson.stdout + .trim() + .split('\n') + .filter(Boolean) + .map((line) => JSON.parse(line) as { name: string; description: string }); + + // Filter to priority labels (P followed by a digit) and package labels (pkg: prefix) + const priorityLabels = allLabels.filter((l) => /^P\d/.test(l.name)); + const packageLabels = allLabels.filter((l) => l.name.startsWith('pkg:')); + const candidateLabels = [...priorityLabels, ...packageLabels]; + + const labelResult = await flue.prompt( + `Label the following GitHub issue based on our Triage Report which summarizes what we learned in our attempt to reproduce, diagnose, and fix the issue. + +Select the most appropriate labels from the list below. Use the label descriptions to guide your decision, combined with the triage report's cause and impact analysis. + +### Rules +- Select exactly ONE priority label based on the severity and impact of the bug. Pay close attention to the "Cause" and "Impact" sections of the triage report. +- You must select ONE priorty label! If you are not sure, just use your best judgement based on the label descriptions and the findings of the triage report. +- Select 0-3 package labels based on where where the issue lives (or most likely lives) in the monorepo. The triage report's diagnosis should make it clear. If you cannot confidently determine the affected package(s), return an empty array for packages. +- Return the exact label names as they appear above — do not modify them. + +### Priority Labels (select exactly one) +${priorityLabels.map((l) => `- **${l.name}**: ${l.description || '(no description)'}`).join('\n')} + +### Package Labels (select zero or more) +${packageLabels.map((l) => `- **${l.name}**: ${l.description || '(no description)'}`).join('\n')} + +--- + + +# ${issue.title} + +${issue.body} + + + +${comment} + +`, + { result: labelResultSchema }, + ); + + const labelsToAdd = [ + ...(labelResult.priority ? [labelResult.priority] : []), + ...labelResult.packages, + ].filter((name) => candidateLabels.some((l) => l.name === name)); + + if (labelsToAdd.length > 0) { + const labelFlags = labelsToAdd.map((l) => `--add-label ${JSON.stringify(l)}`).join(' '); + await flue.shell(`gh issue edit ${issueNumber} ${labelFlags}`, { + env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN }, + }); + } } else if (reproduceResult.skipped) { // Triage was skipped due to a runner limitation. Keep "needs triage" so a // maintainer can still pick it up, and add "auto triage skipped" to prevent @@ -142,9 +217,14 @@ Return only "yes" or "no" inside the ---RESULT_START--- / ---RESULT_END--- block await flue.shell(`gh issue edit ${issueNumber} --add-label "auto triage skipped"`, { env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN }, }); + } else { + // Not reproducible: add "needs repro" and remove "needs triage". + // We handle both labels here (instead of just adding "needs repro") to avoid + // the issue-labeled.yml workflow posting a duplicate auto-comment. + await flue.shell( + `gh issue edit ${issueNumber} --add-label "needs repro" --remove-label "needs triage"`, + { env: { GH_TOKEN: flue.secrets.GITHUB_TOKEN } }, + ); } - - // If not reproducible: "needs triage" label stays. - // The loop continues when the author (or another user) replies. return { reproduceResult, diagnoseResult, fixResult, isPushed }; } diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index 82484ec91d8a..e928dabadd76 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -14,14 +14,12 @@ concurrency: jobs: triage: - # 1. Skip old issues (only run on issues created after this workflow was created) - # 2. Skip issues with "auto triage skipped" label - # 3. Skip pull requests (issues only) - # 4. One of these conditions must be met: - # 4a. Issue was just created - # 4b. Issue comment was just created, and "needs triage" label exists + # 1. Skip issues with "auto triage skipped" label + # 2. Skip pull requests (issues only) + # 3. One of these conditions must be met: + # 3a. Issue was just created + # 3b. Issue comment was just created, and "needs triage" label exists if: >- - github.event.issue.created_at >= '2026-02-11' && !contains(github.event.issue.labels.*.name, 'auto triage skipped') && !github.event.issue.pull_request && ((github.event.action == 'opened') || @@ -35,6 +33,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Configure Git identity + run: | + git config user.name "astrobot-houston" + git config user.email "fred+astrobot@astro.build" + - name: Setup PNPM uses: pnpm/action-setup@v4 diff --git a/packages/astro/src/core/config/merge.ts b/packages/astro/src/core/config/merge.ts index 2344b0f8ef34..6cfa2778d608 100644 --- a/packages/astro/src/core/config/merge.ts +++ b/packages/astro/src/core/config/merge.ts @@ -40,8 +40,13 @@ function mergeConfigRecursively( } } - // for server.allowedHosts, if the value is a boolean - if (key === 'allowedHosts' && rootPath === 'server' && typeof existing === 'boolean') { + // for server.allowedHosts, if either value is a boolean, don't merge as arrays + if ( + key === 'allowedHosts' && + rootPath === 'server' && + (typeof existing === 'boolean' || typeof value === 'boolean') + ) { + merged[key] = typeof value === 'boolean' ? value : existing; continue; } diff --git a/packages/astro/test/units/config/config-merge.test.js b/packages/astro/test/units/config/config-merge.test.js new file mode 100644 index 000000000000..e269b454a0c8 --- /dev/null +++ b/packages/astro/test/units/config/config-merge.test.js @@ -0,0 +1,20 @@ +import * as assert from 'node:assert/strict'; +import { describe, it } from 'node:test'; +import { mergeConfig } from '../../../dist/core/config/index.js'; + +describe('mergeConfig', () => { + it('keeps server.allowedHosts as boolean', () => { + const defaults = { + server: { + allowedHosts: [], + }, + }; + const overrides = { + server: { + allowedHosts: true, + }, + }; + const merged = mergeConfig(defaults, overrides); + assert.equal(merged.server.allowedHosts, true); + }); +});