mirror of https://github.com/sveltejs/svelte
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
7.2 KiB
236 lines
7.2 KiB
name: pkg.pr.new
|
|
on:
|
|
pull_request_target:
|
|
types: [opened, synchronize]
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
inputs:
|
|
sha:
|
|
description: 'Commit SHA to build'
|
|
required: true
|
|
type: string
|
|
|
|
permissions: {}
|
|
|
|
jobs:
|
|
build:
|
|
# Skip pull_request_target events from forks — maintainers can use workflow_dispatch instead
|
|
if: >
|
|
github.event_name != 'pull_request_target' ||
|
|
github.event.pull_request.head.repo.full_name == github.repository
|
|
runs-on: ubuntu-latest
|
|
# No permissions — this job runs user-controlled code
|
|
permissions: {}
|
|
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
# For pull_request_target, check out the PR head.
|
|
# For workflow_dispatch, check out the manually specified SHA.
|
|
# For push, fall back to the push SHA.
|
|
ref: ${{ github.event.pull_request.head.sha || inputs.sha || github.sha }}
|
|
|
|
- uses: pnpm/action-setup@v4
|
|
- uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 22.x
|
|
cache: pnpm
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Build
|
|
run: pnpm build
|
|
|
|
- run: pnpx pkg-pr-new publish --comment=off --json output.json --compact --no-template './packages/svelte'
|
|
|
|
- name: Upload output
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: output
|
|
path: ./output.json
|
|
|
|
# Sanitizes the untrusted output from the build job before it's consumed by
|
|
# jobs with elevated permissions. This ensures that only known package names
|
|
# and valid SHA prefixes make it through.
|
|
sanitize:
|
|
needs: build
|
|
runs-on: ubuntu-latest
|
|
|
|
permissions: {}
|
|
|
|
steps:
|
|
- name: Download artifact
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: output
|
|
|
|
- name: Sanitize output
|
|
uses: actions/github-script@v8
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
const raw = JSON.parse(fs.readFileSync('output.json', 'utf8'));
|
|
|
|
const ALLOWED_PACKAGES = new Set(['svelte']);
|
|
const SHA_PATTERN = /^[0-9a-f]{7}$/;
|
|
|
|
const packages = (raw.packages || [])
|
|
.filter(p => {
|
|
if (!ALLOWED_PACKAGES.has(p.name)) {
|
|
console.log(`Skipping unexpected package: ${JSON.stringify(p.name)}`);
|
|
return false;
|
|
}
|
|
const sha = p.url?.replace(/^.+@([^@]+)$/, '$1');
|
|
if (!sha || !SHA_PATTERN.test(sha)) {
|
|
console.log(`Skipping package with invalid SHA: ${JSON.stringify(p.url)}`);
|
|
return false;
|
|
}
|
|
return true;
|
|
})
|
|
.map(p => ({
|
|
name: p.name,
|
|
sha: p.url.replace(/^.+@([^@]+)$/, '$1'),
|
|
}));
|
|
|
|
fs.writeFileSync('sanitized-output.json', JSON.stringify({ packages }), 'utf8');
|
|
|
|
- name: Upload sanitized output
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: sanitized-output
|
|
path: ./sanitized-output.json
|
|
|
|
comment:
|
|
needs: sanitize
|
|
if: github.event_name == 'pull_request_target' || github.event_name == 'workflow_dispatch'
|
|
runs-on: ubuntu-latest
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
steps:
|
|
- name: Download sanitized artifact
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: sanitized-output
|
|
|
|
- name: Resolve PR number
|
|
id: pr
|
|
uses: actions/github-script@v8
|
|
with:
|
|
script: |
|
|
if (context.eventName === 'pull_request_target') {
|
|
core.setOutput('number', context.issue.number);
|
|
return;
|
|
}
|
|
|
|
const { data: pulls } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
commit_sha: '${{ inputs.sha }}',
|
|
});
|
|
|
|
const open = pulls.filter(p => p.state === 'open');
|
|
|
|
if (open.length === 0) {
|
|
core.setFailed(`No open PR found for commit ${{ inputs.sha }}`);
|
|
return;
|
|
}
|
|
|
|
if (open.length > 1) {
|
|
const nums = open.map(p => `#${p.number}`).join(', ');
|
|
core.setFailed(`Multiple open PRs found for commit ${{ inputs.sha }}: ${nums}`);
|
|
return;
|
|
}
|
|
|
|
core.setOutput('number', open[0].number);
|
|
|
|
- name: Post or update comment
|
|
uses: actions/github-script@v8
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
script: |
|
|
const fs = require('fs');
|
|
const { packages } = JSON.parse(fs.readFileSync('sanitized-output.json', 'utf8'));
|
|
|
|
if (packages.length === 0) {
|
|
console.log('No valid packages found. Skipping comment.');
|
|
return;
|
|
}
|
|
|
|
const issue_number = parseInt('${{ steps.pr.outputs.number }}', 10);
|
|
|
|
const bot_comment_identifier = `<!-- pkg.pr.new comment -->`;
|
|
|
|
const body = `${bot_comment_identifier}
|
|
|
|
[Playground](https://svelte.dev/playground?version=pr-${issue_number})
|
|
|
|
\`\`\`
|
|
${packages.map(p => `pnpm add https://pkg.pr.new/${p.name}@${issue_number}`).join('\n')}
|
|
\`\`\`
|
|
`;
|
|
|
|
const comments = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number,
|
|
});
|
|
const existing = comments.data.find(c => c.body.includes(bot_comment_identifier));
|
|
|
|
if (existing) {
|
|
await github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: existing.id,
|
|
body,
|
|
});
|
|
} else {
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number,
|
|
body,
|
|
});
|
|
}
|
|
|
|
log:
|
|
needs: sanitize
|
|
if: github.event_name == 'push'
|
|
runs-on: ubuntu-latest
|
|
|
|
permissions: {}
|
|
|
|
steps:
|
|
- name: Download sanitized artifact
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: sanitized-output
|
|
|
|
- name: Log publish info
|
|
uses: actions/github-script@v8
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
const { packages } = JSON.parse(fs.readFileSync('sanitized-output.json', 'utf8'));
|
|
|
|
if (packages.length === 0) {
|
|
console.log('No valid packages found.');
|
|
return;
|
|
}
|
|
|
|
console.log('\n' + '='.repeat(50));
|
|
console.log('Publish Information');
|
|
console.log('='.repeat(50));
|
|
for (const p of packages) {
|
|
console.log(`${p.name} - pnpm add https://pkg.pr.new/${p.name}@${p.sha}`);
|
|
}
|
|
const svelte = packages.find(p => p.name === 'svelte');
|
|
if (svelte) {
|
|
console.log(`\nPlayground: https://svelte.dev/playground?version=commit-${svelte.sha}`);
|
|
}
|
|
console.log('='.repeat(50));
|