Skip to content

Commit 5f7d134

Browse files
authored
release: prepare WebUtils 2.2.0 (#219)
1 parent 1719b08 commit 5f7d134

10 files changed

Lines changed: 112 additions & 22 deletions

File tree

.github/workflows/lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
- name: Check tools sync
8181
run: |
8282
npm run sync:tools
83-
if [ -n "$(git diff --name-only -- index.html README.md sitemap.xml manifest.json llms.txt i18n tools)" ]; then
83+
if [ -n "$(git diff --name-only -- index.html README.md README.en.md sitemap.xml manifest.json llms.txt i18n tools)" ]; then
8484
echo "❌ Error: generated sources are out of sync with tools.json"
8585
echo ""
8686
echo "Please run locally:"
@@ -89,7 +89,7 @@ jobs:
8989
echo " git push --force-with-lease"
9090
echo ""
9191
echo "Diff:"
92-
git diff -- index.html README.md sitemap.xml manifest.json llms.txt i18n tools | head -100
92+
git diff -- index.html README.md README.en.md sitemap.xml manifest.json llms.txt i18n tools | head -100
9393
exit 1
9494
fi
9595
echo "✅ Tools are in sync"

.github/workflows/release.yml

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ jobs:
9494
run: npm run build
9595

9696
- name: Verify generated sources are committed
97-
run: git diff --exit-code -- index.html README.md sitemap.xml manifest.json llms.txt i18n tools
97+
run: git diff --exit-code -- index.html README.md README.en.md sitemap.xml manifest.json llms.txt i18n tools
9898

9999
- name: Scan release tree and verify license files
100100
run: |
@@ -106,19 +106,15 @@ jobs:
106106
VERSION: ${{ steps.version.outputs.version }}
107107
run: npm run build:release
108108

109-
- name: Generate changelog
110-
id: changelog
109+
- name: Read curated release notes
110+
id: notes
111+
env:
112+
VERSION: ${{ steps.version.outputs.version }}
111113
run: |
112-
# Get commits since last tag
113-
LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
114-
if [ -n "$LAST_TAG" ]; then
115-
CHANGELOG=$(git log --pretty=format:"- %s" "$LAST_TAG"..HEAD)
116-
else
117-
CHANGELOG=$(git log --pretty=format:"- %s" -20)
118-
fi
114+
RELEASE_NOTES=$(node scripts/extract-release-notes.mjs "$VERSION")
119115
{
120-
echo "CHANGELOG<<EOF"
121-
echo "$CHANGELOG"
116+
echo "RELEASE_NOTES<<EOF"
117+
echo "$RELEASE_NOTES"
122118
echo "EOF"
123119
} >> "$GITHUB_OUTPUT"
124120
@@ -133,14 +129,15 @@ jobs:
133129
env:
134130
VERSION: ${{ steps.version.outputs.version }}
135131
TOOL_COUNT: ${{ steps.tools.outputs.COUNT }}
136-
CHANGELOG: ${{ steps.changelog.outputs.CHANGELOG }}
137132
with:
138133
tag_name: ${{ steps.version.outputs.tag }}
139134
name: WebUtils ${{ steps.version.outputs.version }}
140135
body: |
141136
## WebUtils ${{ steps.version.outputs.version }}
142137
143-
**${{ steps.tools.outputs.COUNT }}+ 纯前端在线工具集**
138+
**${{ steps.tools.outputs.COUNT }}+ 本地优先的浏览器工具集**
139+
140+
Local-first browser utilities with standalone HTML export and transparent network boundaries.
144141
145142
### 特性
146143
- 静态 HTML 工具集,可导出独立页面
@@ -159,7 +156,7 @@ jobs:
159156
3. 按 README 的隐私与网络边界使用;外部资源或网络工具仍需联网
160157
161158
### 更新日志
162-
${{ steps.changelog.outputs.CHANGELOG }}
159+
${{ steps.notes.outputs.RELEASE_NOTES }}
163160
164161
---
165162

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,38 @@
55
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)
66
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)
77

8+
## [2.2.0] - 2026-08-26
9+
10+
本版本将 WebUtils 从“大量工具页面”收口为可持续维护的本地优先工具集,强化独立导出、隐私边界、浏览器验收和开源贡献入口。
11+
12+
### 新增
13+
14+
- 首页“最近使用”工作流,与搜索、分类、收藏和 URL 状态联动
15+
- 已登记工具的 standalone HTML 导出能力,自动内联仓库自有的共享 CSS/JavaScript
16+
- Playwright Browser Smoke 基线,覆盖首页发现、收藏、最近使用、移动端溢出与 5 个代表工具流程
17+
- 英文项目概览、中英文切换入口与可自动同步的工具数量
18+
19+
### 改进
20+
21+
- 工具规模更新为 1088 个,补齐工具页唯一 H1 及对应结构门禁
22+
- 收紧本地处理、浏览器权限、外部 API/CDN 和离线能力的文档表述,避免泛化的“纯前端即绝对离线”承诺
23+
- JSON 格式化、时间戳转换、URL 编解码与 Base64 工具的键盘、动态状态、Unicode 和文件处理可用性
24+
- Issue/PR 模板与贡献检查清单,补充复现环境、敏感信息与网络边界要求
25+
26+
### 工程与发布
27+
28+
- 单测基线扩展至 68 项,共享工具样式纳入 Stylelint,部署 Actions 升级至 Node.js 24 运行时
29+
- 发布工作流增加版本一致性、历史泄漏、个人路径、许可证、可重现归档与当前 `master` 标签校验
30+
- 部署包与发布归档均包含中英文 README、LICENSE 和 NOTICE,并验证与源文件一致
31+
32+
### 修复
33+
34+
- Base64 Unicode 编解码、文件导入导出与 UTF-8 BOM 保留
35+
- URL 编解码错误恢复、时间戳输入与 JSON 结果动态通知
36+
- 移动端搜索键盘、分类阴影裁剪、首页溢出与多项工具运行时异常
37+
38+
---
39+
840
## [2.1.0] - 2026-05-19
941

1042
工具规模 999 → 1086,抽出共享设计基座并完成全站统一。

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"applicationCategory": "DeveloperApplication",
5555
"operatingSystem": "Any",
5656
"browserRequirements": "Requires JavaScript. Works in Chrome, Firefox, Safari, Edge.",
57-
"softwareVersion": "2.1.0",
57+
"softwareVersion": "2.2.0",
5858
"inLanguage": ["zh-CN", "en"],
5959
"isAccessibleForFree": true,
6060
"offers": {

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "webutils",
3-
"version": "2.1.0",
3+
"version": "2.2.0",
44
"description": "浏览器端工具集;多数工具本地处理,网络类工具按需连接用户指定服务",
55
"type": "module",
66
"private": true,

scripts/extract-release-notes.mjs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import fs from 'node:fs';
2+
import path from 'node:path';
3+
import { fileURLToPath } from 'node:url';
4+
5+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
6+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
7+
const version = process.argv[2] || pkg.version;
8+
const changelog = fs.readFileSync(path.join(root, 'CHANGELOG.md'), 'utf8');
9+
const headings = [...changelog.matchAll(/^## \[([^\]]+)\][^\n]*$/gm)];
10+
const headingIndex = headings.findIndex((match) => match[1] === version);
11+
12+
if (headingIndex === -1) {
13+
throw new Error(`CHANGELOG.md does not contain release notes for ${version}`);
14+
}
15+
16+
const start = headings[headingIndex].index + headings[headingIndex][0].length;
17+
const end = headings[headingIndex + 1]?.index ?? changelog.length;
18+
const notes = changelog
19+
.slice(start, end)
20+
.replace(/^\s+|\s+$/g, '')
21+
.replace(/\n---\s*$/, '');
22+
23+
if (!notes) {
24+
throw new Error(`CHANGELOG.md release notes for ${version} are empty`);
25+
}
26+
27+
process.stdout.write(`${notes}\n`);

tests/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ npm test # 运行全部测试(node tests/run.js)
2222
| `html-structure.test.js` | 每个工具 HTML 的 `<head>`:doctype、lang、SEO 元数据、canonical |
2323
| `redirects.test.js` | `_redirects``vercel.json` 重定向目标有效、两份配置一致 |
2424
| `assets.test.js` | 静态资源与 i18n:sw 预缓存清单、manifest 图标/快捷方式、en/zh 翻译键一一对应 |
25+
| `release-notes.test.js` | 发布说明:按当前版本提取 CHANGELOG 段落,拒绝缺失版本与跨版本内容 |
2526

2627
## 新增测试
2728

tests/release-notes.test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import path from 'node:path';
2+
import { execFileSync } from 'node:child_process';
3+
import { section, test, assert, readText, ROOT } from './_harness.js';
4+
5+
section('发布说明');
6+
7+
const pkg = JSON.parse(readText('package.json'));
8+
const script = path.join(ROOT, 'scripts', 'extract-release-notes.mjs');
9+
10+
test(`可提取当前版本 ${pkg.version} 的独立更新日志`, () => {
11+
const notes = execFileSync(process.execPath, [script, pkg.version], {
12+
cwd: ROOT,
13+
encoding: 'utf8'
14+
});
15+
16+
assert(notes.includes('### 新增'), '发布说明缺少“新增”段落');
17+
assert(!notes.includes('## [2.1.0]'), '发布说明不应包含上一版本标题');
18+
assert(!notes.trimEnd().endsWith('---'), '发布说明不应以 CHANGELOG 分隔线结尾');
19+
});
20+
21+
test('拒绝提取 CHANGELOG 中不存在的版本', () => {
22+
let rejected = false;
23+
try {
24+
execFileSync(process.execPath, [script, '999.0.0'], {
25+
cwd: ROOT,
26+
stdio: 'pipe'
27+
});
28+
} catch {
29+
rejected = true;
30+
}
31+
assert(rejected, '不存在的版本应返回非零退出码');
32+
});

tests/run.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ const TEST_FILES = [
1616
'redirects.test.js',
1717
'assets.test.js',
1818
'standalone-export.test.js',
19-
'recent-tools.test.js'
19+
'recent-tools.test.js',
20+
'release-notes.test.js'
2021
];
2122

2223
let crashed = 0;

0 commit comments

Comments
 (0)