chore(ci): 重构发布流程为手动触发方式并添加behavior-tree包发布支持

This commit is contained in:
YHH
2025-10-27 09:47:59 +08:00
parent d2ad295b48
commit 4cee396ea9
8 changed files with 387 additions and 160 deletions

View File

@@ -73,7 +73,8 @@ jobs:
path: | path: |
packages/core/bin packages/core/bin
packages/editor-core/dist packages/editor-core/dist
key: ${{ runner.os }}-ts-build-${{ hashFiles('packages/core/src/**', 'packages/editor-core/src/**') }} packages/behavior-tree/bin
key: ${{ runner.os }}-ts-build-${{ hashFiles('packages/core/src/**', 'packages/editor-core/src/**', 'packages/behavior-tree/src/**') }}
restore-keys: | restore-keys: |
${{ runner.os }}-ts-build- ${{ runner.os }}-ts-build-
@@ -85,6 +86,11 @@ jobs:
cd packages/editor-core cd packages/editor-core
npm run build npm run build
- name: Build behavior-tree package
run: |
cd packages/behavior-tree
npm run build
- name: Build Tauri app - name: Build Tauri app
uses: tauri-apps/tauri-action@v0.5 uses: tauri-apps/tauri-action@v0.5
env: env:

View File

@@ -1,30 +1,34 @@
name: Release name: Release NPM Packages
on: on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
dry_run: package:
description: 'Dry run (仅预览,不实际发布)' description: '选择要发布的包'
type: boolean required: true
default: false type: choice
required: false options:
- core
- behavior-tree
version:
description: '版本号 (例如: 2.2.9 或 1.0.1)'
required: true
type: string
permissions: permissions:
contents: write contents: write
issues: write
pull-requests: write pull-requests: write
id-token: write id-token: write
jobs: jobs:
release-core: release-package:
name: Release Core Package name: Release ${{ github.event.inputs.package }} Package
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js - name: Setup Node.js
@@ -37,32 +41,54 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
- name: Run tests - name: Build core package (if needed)
if: ${{ github.event.inputs.package == 'behavior-tree' }}
run: | run: |
cd packages/core cd packages/core
npm run build
- name: Run tests
run: |
cd packages/${{ github.event.inputs.package }}
npm run test:ci npm run test:ci
- name: Update version
run: |
cd packages/${{ github.event.inputs.package }}
npm version ${{ github.event.inputs.version }} --no-git-tag-version
- name: Build package - name: Build package
run: | run: |
cd packages/core cd packages/${{ github.event.inputs.package }}
npm run build:npm npm run build:npm
- name: Release (Dry Run) - name: Publish to npm
if: ${{ github.event.inputs.dry_run == 'true' }}
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: | run: |
cd packages/core cd packages/${{ github.event.inputs.package }}/dist
npx semantic-release --dry-run npm publish
- name: Release - name: Create Pull Request
if: ${{ github.event.inputs.dry_run != 'true' }} uses: peter-evans/create-pull-request@v6
env: with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} commit-message: "chore(${{ github.event.inputs.package }}): release v${{ github.event.inputs.version }}"
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} branch: release/${{ github.event.inputs.package }}-v${{ github.event.inputs.version }}
run: | delete-branch: true
cd packages/core title: "chore(${{ github.event.inputs.package }}): Release v${{ github.event.inputs.version }}"
npx semantic-release body: |
## 🚀 Release v${{ github.event.inputs.version }}
此 PR 更新 `@esengine/${{ github.event.inputs.package }}` 包的版本号
### 变更
- ✅ 已发布到 npm: [@esengine/${{ github.event.inputs.package }}@${{ github.event.inputs.version }}](https://www.npmjs.com/package/@esengine/${{ github.event.inputs.package }}/v/${{ github.event.inputs.version }})
- ✅ 更新 `packages/${{ github.event.inputs.package }}/package.json` → `${{ github.event.inputs.version }}`
---
*此 PR 由发布工作流自动创建*
labels: |
release
${{ github.event.inputs.package }}
automated pr

View File

@@ -1,58 +0,0 @@
{
"branches": ["master", "main"],
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "angular",
"releaseRules": [
{ "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" },
{ "type": "revert", "release": "patch" },
{ "type": "docs", "release": false },
{ "type": "chore", "release": false },
{ "type": "refactor", "release": "patch" },
{ "type": "test", "release": false },
{ "type": "build", "release": false },
{ "type": "ci", "release": false }
]
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "angular",
"writerOpts": {
"commitsSort": ["subject", "scope"]
}
}
],
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md",
"changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file."
}
],
[
"@semantic-release/npm",
{
"npmPublish": false
}
],
[
"@semantic-release/git",
{
"assets": ["CHANGELOG.md", "package.json", "package-lock.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
[
"@semantic-release/github",
{
"assets": []
}
]
]
}

View File

@@ -0,0 +1,128 @@
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
console.log('🚀 使用 Rollup 构建npm包...');
async function main() {
try {
// 清理旧的dist目录
if (fs.existsSync('./dist')) {
console.log('🧹 清理旧的构建文件...');
execSync('rimraf ./dist', { stdio: 'inherit' });
}
// 执行Rollup构建
console.log('📦 执行 Rollup 构建...');
execSync('npx rollup -c rollup.config.cjs', { stdio: 'inherit' });
// 生成package.json
console.log('📋 生成 package.json...');
generatePackageJson();
// 复制其他文件
console.log('📁 复制必要文件...');
copyFiles();
// 输出构建结果
showBuildResults();
console.log('✅ 构建完成!');
console.log('\n🚀 发布命令:');
console.log('cd dist && npm publish');
} catch (error) {
console.error('❌ 构建失败:', error.message);
process.exit(1);
}
}
function generatePackageJson() {
const sourcePackage = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
const distPackage = {
name: sourcePackage.name,
version: sourcePackage.version,
description: sourcePackage.description,
main: 'index.cjs',
module: 'index.mjs',
unpkg: 'index.umd.js',
types: 'index.d.ts',
exports: {
'.': {
import: './index.mjs',
require: './index.cjs',
types: './index.d.ts'
}
},
files: [
'index.mjs',
'index.mjs.map',
'index.cjs',
'index.cjs.map',
'index.umd.js',
'index.umd.js.map',
'index.es5.js',
'index.es5.js.map',
'index.d.ts'
],
keywords: [
'ecs',
'behavior-tree',
'ai',
'game-ai',
'entity-component-system',
'typescript',
'cocos-creator',
'laya',
'rollup'
],
author: sourcePackage.author,
license: sourcePackage.license,
repository: sourcePackage.repository,
bugs: sourcePackage.bugs,
homepage: sourcePackage.homepage,
peerDependencies: sourcePackage.peerDependencies,
engines: {
node: '>=16.0.0'
},
sideEffects: false
};
fs.writeFileSync('./dist/package.json', JSON.stringify(distPackage, null, 2));
}
function copyFiles() {
const filesToCopy = [
// 如果有 README 或其他文件需要复制,可以在这里添加
];
filesToCopy.forEach(({ src, dest }) => {
if (fs.existsSync(src)) {
fs.copyFileSync(src, dest);
console.log(` ✓ 复制: ${path.basename(dest)}`);
} else {
console.log(` ⚠️ 文件不存在: ${src}`);
}
});
if (filesToCopy.length === 0) {
console.log(' 没有需要复制的文件');
}
}
function showBuildResults() {
const distDir = './dist';
const files = ['index.mjs', 'index.cjs', 'index.umd.js', 'index.es5.js', 'index.d.ts'];
console.log('\n📊 构建结果:');
files.forEach(file => {
const filePath = path.join(distDir, file);
if (fs.existsSync(filePath)) {
const size = fs.statSync(filePath).size;
console.log(` ${file}: ${(size / 1024).toFixed(1)}KB`);
}
});
}
main().catch(console.error);

View File

@@ -31,8 +31,10 @@
"build": "npm run build:ts", "build": "npm run build:ts",
"build:watch": "tsc --watch", "build:watch": "tsc --watch",
"rebuild": "npm run clean && npm run build", "rebuild": "npm run clean && npm run build",
"build:npm": "npm run build && node build-rollup.cjs",
"test": "jest --config jest.config.cjs", "test": "jest --config jest.config.cjs",
"test:watch": "jest --watch --config jest.config.cjs" "test:watch": "jest --watch --config jest.config.cjs",
"test:ci": "jest --ci --coverage --config jest.config.cjs"
}, },
"author": "yhh", "author": "yhh",
"license": "MIT", "license": "MIT",
@@ -40,10 +42,20 @@
"@esengine/ecs-framework": "^2.2.8" "@esengine/ecs-framework": "^2.2.8"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.28.3",
"@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1",
"@babel/plugin-transform-optional-chaining": "^7.27.1",
"@babel/preset-env": "^7.28.3",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-commonjs": "^28.0.3",
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-terser": "^0.4.4",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^20.19.17", "@types/node": "^20.19.17",
"jest": "^29.7.0", "jest": "^29.7.0",
"rimraf": "^5.0.0", "rimraf": "^5.0.0",
"rollup": "^4.42.0",
"rollup-plugin-dts": "^6.2.1",
"ts-jest": "^29.4.0", "ts-jest": "^29.4.0",
"typescript": "^5.8.3" "typescript": "^5.8.3"
}, },

View File

@@ -0,0 +1,186 @@
const resolve = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const terser = require('@rollup/plugin-terser');
const babel = require('@rollup/plugin-babel');
const dts = require('rollup-plugin-dts').default;
const { readFileSync } = require('fs');
const pkg = JSON.parse(readFileSync('./package.json', 'utf8'));
const banner = `/**
* @esengine/behavior-tree v${pkg.version}
* 完全ECS化的行为树系统
*
* @author ${pkg.author}
* @license ${pkg.license}
*/`;
const external = ['@esengine/ecs-framework'];
const commonPlugins = [
resolve({
browser: true,
preferBuiltins: false
}),
commonjs({
include: /node_modules/
}),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
extensions: ['.js', '.ts']
})
];
module.exports = [
// ES模块构建
{
input: 'bin/index.js',
output: {
file: 'dist/index.mjs',
format: 'es',
banner,
sourcemap: true,
exports: 'named'
},
plugins: [
...commonPlugins,
terser({
format: {
comments: /^!/
}
})
],
external,
treeshake: {
moduleSideEffects: false,
propertyReadSideEffects: false,
unknownGlobalSideEffects: false
}
},
// CommonJS构建
{
input: 'bin/index.js',
output: {
file: 'dist/index.cjs',
format: 'cjs',
banner,
sourcemap: true,
exports: 'named'
},
plugins: [
...commonPlugins,
terser({
format: {
comments: /^!/
}
})
],
external,
treeshake: {
moduleSideEffects: false
}
},
// UMD构建
{
input: 'bin/index.js',
output: {
file: 'dist/index.umd.js',
format: 'umd',
name: 'BehaviorTree',
banner,
sourcemap: true,
exports: 'named',
globals: {
'@esengine/ecs-framework': 'ECS'
}
},
plugins: [
...commonPlugins,
terser({
format: {
comments: /^!/
}
})
],
external,
treeshake: {
moduleSideEffects: false
}
},
// ES5兼容构建
{
input: 'bin/index.js',
output: {
file: 'dist/index.es5.js',
format: 'cjs',
banner: banner + '\n// ES5 Compatible Build for legacy JavaScript environments',
sourcemap: true,
exports: 'named'
},
plugins: [
resolve({
browser: true,
preferBuiltins: false
}),
commonjs({
include: /node_modules/
}),
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
extensions: ['.js', '.ts'],
presets: [
['@babel/preset-env', {
targets: {
browsers: ['ie >= 9', 'chrome >= 30', 'firefox >= 30', 'safari >= 8']
},
modules: false,
loose: true,
forceAllTransforms: true
}]
],
plugins: [
'@babel/plugin-transform-optional-chaining',
'@babel/plugin-transform-nullish-coalescing-operator'
]
}),
terser({
ecma: 5,
format: {
comments: /^!/
},
compress: {
drop_console: false,
drop_debugger: false
}
})
],
external,
treeshake: {
moduleSideEffects: false
}
},
// 类型定义构建
{
input: 'bin/index.d.ts',
output: {
file: 'dist/index.d.ts',
format: 'es',
banner: `/**
* @esengine/behavior-tree v${pkg.version}
* TypeScript definitions
*/`
},
plugins: [
dts({
respectExternal: true
})
],
external: ['@esengine/ecs-framework']
}
];

View File

@@ -1,68 +0,0 @@
{
"branches": ["master", "main"],
"tagFormat": "core-v${version}",
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "angular",
"releaseRules": [
{ "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" },
{ "type": "revert", "release": "patch" },
{ "type": "docs", "release": false },
{ "type": "chore", "release": false },
{ "type": "refactor", "release": "patch" },
{ "type": "test", "release": false },
{ "type": "build", "release": false },
{ "type": "ci", "release": false }
],
"parserOpts": {
"noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"]
}
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "angular",
"writerOpts": {
"commitsSort": ["subject", "scope"]
}
}
],
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md",
"changelogTitle": "# @esengine/ecs-framework Changelog\n\nAll notable changes to the core package will be documented in this file."
}
],
[
"@semantic-release/npm",
{
"pkgRoot": "dist",
"tarballDir": "release"
}
],
[
"@semantic-release/git",
{
"assets": ["CHANGELOG.md", "package.json", "package-lock.json"],
"message": "chore(core): release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
[
"@semantic-release/github",
{
"assets": [
{
"path": "release/*.tgz",
"label": "npm package"
}
]
}
]
]
}

View File

@@ -34,11 +34,6 @@
"build:watch": "tsc --watch", "build:watch": "tsc --watch",
"rebuild": "npm run clean && npm run build", "rebuild": "npm run clean && npm run build",
"build:npm": "npm run build && node build-rollup.cjs", "build:npm": "npm run build && node build-rollup.cjs",
"publish:npm": "npm run build:npm && cd dist && npm publish",
"publish:patch": "npm version patch && npm run build:npm && cd dist && npm publish",
"publish:minor": "npm version minor && npm run build:npm && cd dist && npm publish",
"publish:major": "npm version major && npm run build:npm && cd dist && npm publish",
"preversion": "npm run rebuild",
"test": "jest --config jest.config.cjs", "test": "jest --config jest.config.cjs",
"test:watch": "jest --watch --config jest.config.cjs", "test:watch": "jest --watch --config jest.config.cjs",
"test:performance": "jest --config jest.performance.config.cjs", "test:performance": "jest --config jest.performance.config.cjs",