fix: #1093 修复开启流式虚拟光标时,代码块被破坏的问题 #4
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: PR Merge cherry-markdown Dev NPM Preview | |
on: | |
pull_request_target: | |
types: [closed] | |
paths: | |
- "packages/cherry-markdown/**" | |
permissions: | |
contents: read | |
pull-requests: write | |
issues: write | |
jobs: | |
dev-deploy: | |
# 不需要在fork仓库的pr中运行, 仅当pr合并时运行 | |
if: github.repository == 'Tencent/cherry-markdown' && github.event.pull_request.merged == true | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
- name: Get Merge Commit SHA | |
run: echo "COMMIT_SHORT_SHA=${GITHUB_SHA:0:7}" >> $GITHUB_ENV | |
- name: Install dependencies | |
run: sudo apt-get install -y moreutils | |
- name: Update package.json | |
working-directory: ./packages/cherry-markdown | |
run: | | |
BASE_VERSION=$(jq -r .version package.json) | |
VERSION="${BASE_VERSION}-dev.$(date +'%Y%m%d%H%M').${{ env.COMMIT_SHORT_SHA }}" | |
jq --arg name "@cherry-markdown/cherry-markdown-dev" \ | |
--arg version "$VERSION" \ | |
'.name = $name | .version = $version | del(.scripts.publish?)' package.json | sponge package.json | |
echo "PACKAGE_VERSION=$VERSION" >> $GITHUB_ENV | |
echo "PACKAGE_NAME=@cherry-markdown/cherry-markdown-dev" >> $GITHUB_ENV | |
- name: Update README | |
working-directory: ./packages/cherry-markdown | |
run: | | |
cat <<-EOF > README.md | |
**⚠️ 开发预览警告 / Development Preview Warning** | |
此版本为临时测试版(${PACKAGE_NAME}@${PACKAGE_VERSION}),禁止在生产环境使用! | |
最后更新时间:`$(date +'%Y-%m-%d %H:%M:%S')` | |
This is a development preview version (${PACKAGE_NAME}@${PACKAGE_VERSION}), do NOT use in production! | |
Last updated: `$(date +'%Y-%m-%d %H:%M:%S')` | |
EOF | |
- name: Set up Node.js | |
uses: actions/setup-node@v4 | |
with: | |
node-version: 18 | |
registry-url: https://registry.npmjs.org/ | |
cache: yarn | |
- name: Install and build | |
working-directory: ./packages/cherry-markdown | |
run: yarn install && yarn build | |
- name: npm publish | |
working-directory: ./packages/cherry-markdown | |
run: npm publish | |
env: | |
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
- name: Post comments | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
// 工具函数:增强型 Issue 提取 | |
const extractValidReferences = (text) => { | |
if (!text) return []; | |
// 匹配当前仓库格式的 #数字 或 owner/repo#数字(精确匹配当前仓库) | |
const repoRegex = new RegExp( | |
`(?:^|\\s)(?:#(\\d+)|${context.repo.owner}/${context.repo.repo}#(\\d+))`, | |
'gm' | |
); | |
const matches = text.matchAll(repoRegex) || []; | |
return Array.from(matches, match => { | |
// 优先捕获跨仓库引用(第二捕获组) | |
return match[2] ? parseInt(match[2], 10) : parseInt(match[1], 10); | |
}).filter(num => !isNaN(num)); | |
}; | |
// 验证 Issue/PR 归属 | |
const isValidTarget = async (number) => { | |
try { | |
await github.rest.issues.get({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: number, | |
headers: { "X-GitHub-Api-Version": "2022-11-28" } | |
}); | |
return true; | |
} catch (error) { | |
// 404 表示目标不存在或不属于本仓库 | |
if (error.status === 404) return false; | |
// 其他错误视为无效 | |
console.error('Validation error:', error); | |
return false; | |
} | |
}; | |
// 异步批次处理器 | |
const batchProcessor = async (items, processor, batchSize = 10) => { | |
const results = []; | |
for (let i = 0; i < items.length; i += batchSize) { | |
const batch = items.slice(i, i + batchSize); | |
const batchResults = await Promise.all(batch.map(processor)); | |
results.push(...batchResults); | |
// 避免触发 GitHub API 速率限制 | |
await new Promise(resolve => setTimeout(resolve, 500)); | |
} | |
return results; | |
}; | |
try { | |
// 阶段 1:数据收集 | |
const targets = new Set(); | |
// 收集当前 PR 自身 | |
if (context.payload.pull_request?.number) { | |
targets.add(context.payload.pull_request.number); | |
} | |
// 收集 PR 相关内容 | |
if (context.payload.pull_request) { | |
const { data: pr } = await github.rest.pulls.get({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
pull_number: context.payload.pull_request.number, | |
headers: { "X-GitHub-Api-Version": "2022-11-28" } | |
}); | |
// 处理标题和正文 | |
[pr.title, pr.body].forEach(text => { | |
extractValidReferences(text).forEach(num => targets.add(num)); | |
}); | |
// 处理评论(常规评论 + 代码评审评论) | |
const [comments, reviews] = await Promise.all([ | |
github.rest.issues.listComments({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: context.payload.pull_request.number, | |
per_page: 100 | |
}), | |
github.rest.pulls.listReviewComments({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
pull_number: context.payload.pull_request.number, | |
per_page: 100 | |
}) | |
]); | |
[...comments.data, ...reviews.data].forEach(comment => { | |
extractValidReferences(comment.body).forEach(num => targets.add(num)); | |
}); | |
} | |
// 处理提交信息 | |
context.payload.commits?.forEach(commit => { | |
extractValidReferences(commit.message).forEach(num => targets.add(num)); | |
}); | |
// 阶段 2:数据验证 | |
const candidateNumbers = Array.from(targets); | |
console.log('Candidate targets:', candidateNumbers); | |
// 批次验证有效性 | |
const validationResults = await batchProcessor( | |
candidateNumbers, | |
async num => ({ num, valid: await isValidTarget(num) }) | |
); | |
const validNumbers = validationResults | |
.filter(r => r.valid) | |
.map(r => r.num); | |
console.log('Validated targets:', validNumbers); | |
if (validNumbers.length === 0) { | |
console.log('No valid targets found'); | |
return; | |
} | |
// 阶段 3:评论发送 | |
const commentTemplate = `📦 **cherry-markdown dev preview published** | |
⚠️ **注意**: 此版本为开发预览版,禁止在生产环境使用! | |
⚠️ **Note**: This version is a developer preview and should not be used in production environments! | |
**Install [NPM](https://www.npmjs.com/package/${process.env.PACKAGE_NAME}/v/${process.env.PACKAGE_VERSION}) with** : | |
\`\`\`bash | |
npm install ${process.env.PACKAGE_NAME}@${process.env.PACKAGE_VERSION} | |
\`\`\` | |
`; | |
// 并发发送控制(每秒 2 个请求) | |
await batchProcessor( | |
validNumbers, | |
async number => { | |
try { | |
await github.rest.issues.createComment({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: number, | |
body: commentTemplate, | |
headers: { "X-GitHub-Api-Version": "2022-11-28" } | |
}); | |
console.log(`Commented on #${number}`); | |
} catch (error) { | |
console.error(`Failed to comment on #${number}:`, error.message); | |
} | |
}, | |
); | |
} catch (error) { | |
console.error('Workflow failed:', error); | |
// 仅在当前 PR 上报告错误 | |
if (context.payload.pull_request?.number) { | |
await github.rest.issues.createComment({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
issue_number: context.payload.pull_request.number, | |
body: `🚨 发布流程失败: ${error.message}` | |
}); | |
} | |
} |