Enhance release workflow with auto-release on merge and PR validation

Co-authored-by: Fu-Jie <33599649+Fu-Jie@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-12-31 12:06:31 +00:00
parent 10bddd2026
commit 5b8750c438
4 changed files with 457 additions and 196 deletions

View File

@@ -7,7 +7,9 @@
# What it does:
# 1. Compares plugin versions between base and head branches
# 2. Generates a summary of version changes
# 3. Comments on the PR with the changes (optional)
# 3. Comments on the PR with the changes
# 4. FAILS the check if plugin files are modified but no version update is detected
# (enforces version bump requirement for plugin changes)
name: Plugin Version Check / 插件版本检查
@@ -82,16 +84,54 @@ jobs:
echo 'EOF'
} >> $GITHUB_OUTPUT
- name: Comment on PR
- name: Check PR description for update notes
id: check_description
if: steps.compare.outputs.has_changes == 'true'
uses: actions/github-script@v7
with:
script: |
const prBody = context.payload.pull_request.body || '';
// Check if PR has meaningful description (at least 20 characters, excluding whitespace)
// Use [\s\S]*? for multiline HTML comment matching (compatible across JS engines)
const cleanBody = prBody.replace(/\s+/g, '').replace(/<!--[\s\S]*?-->/g, '');
const hasDescription = cleanBody.length >= 20;
console.log(`PR body length (cleaned): ${cleanBody.length}`);
console.log(`Has meaningful description: ${hasDescription}`);
core.setOutput('has_description', hasDescription.toString());
return hasDescription;
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const hasChanges = '${{ steps.compare.outputs.has_changes }}' === 'true';
const hasDescription = '${{ steps.check_description.outputs.has_description }}' === 'true';
const changes = `${{ steps.compare.outputs.changes }}`;
const body = `## 🔍 Plugin Version Changes / 插件版本变化
let statusIcon = '';
let statusMessage = '';
${changes}
if (hasChanges && hasDescription) {
statusIcon = '✅';
statusMessage = '版本更新检测通过PR 包含版本变化和更新说明。\n\nVersion check passed! PR contains version changes and update description.';
} else if (hasChanges && !hasDescription) {
statusIcon = '⚠️';
statusMessage = '检测到版本更新,但 PR 描述过短。请在 PR 描述中添加更新说明(至少 20 个字符)。\n\nVersion update detected, but PR description is too short. Please add update notes in PR description (at least 20 characters).';
} else {
statusIcon = '❌';
statusMessage = '未检测到版本更新!修改插件文件时必须更新版本号。\n\nNo version update detected! You must update the version number when modifying plugin files.';
}
const body = `## ${statusIcon} Plugin Version Check / 插件版本检查
${statusMessage}
---
${hasChanges ? `### 版本变化 / Version Changes\n\n${changes}` : ''}
---
*This comment was generated automatically. / 此评论由自动生成。*
@@ -106,11 +146,10 @@ jobs:
const botComment = comments.find(comment =>
(comment.user.login === 'github-actions[bot]' || comment.user.type === 'Bot') &&
comment.body.includes('Plugin Version Changes')
comment.body.includes('Plugin Version Check')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -118,7 +157,6 @@ jobs:
body: body,
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -127,6 +165,36 @@ jobs:
});
}
- name: Enforce version update requirement
if: steps.compare.outputs.has_changes == 'false'
run: |
echo "::error::❌ 未检测到版本更新!修改插件文件时必须更新版本号。"
echo "::error::No version update detected! You must update the version number when modifying plugin files."
echo ""
echo "请在插件文件的 docstring 中更新版本号:"
echo "Please update the version in your plugin's docstring:"
echo ""
echo '"""'
echo 'title: Your Plugin'
echo 'version: 0.2.0 # <- 更新此处 / Update this'
echo '...'
echo '"""'
exit 1
- name: Enforce PR description requirement
if: steps.compare.outputs.has_changes == 'true' && steps.check_description.outputs.has_description == 'false'
run: |
echo "::error::⚠️ PR 描述过短!请添加更新说明。"
echo "::error::PR description is too short! Please add update notes."
echo ""
echo "请在 PR 描述中添加以下内容:"
echo "Please add the following to your PR description:"
echo ""
echo "- 更新了哪些功能 / What features were updated"
echo "- 修复了哪些问题 / What issues were fixed"
echo "- 其他重要变更 / Other important changes"
exit 1
- name: Summary
run: |
echo "## 🔍 Plugin Version Check Results" >> $GITHUB_STEP_SUMMARY
@@ -136,6 +204,11 @@ jobs:
echo "✅ **Version changes detected!**" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
cat changes.md >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.check_description.outputs.has_description }}" = "true" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ **PR description check passed!**" >> $GITHUB_STEP_SUMMARY
fi
else
echo " **No version changes detected.**" >> $GITHUB_STEP_SUMMARY
echo " **No version changes detected - check failed!**" >> $GITHUB_STEP_SUMMARY
fi

View File

@@ -5,24 +5,34 @@
# 此工作流自动化 OpenWebUI 插件的发布流程。
#
# Triggers:
# - Push to main branch when plugins are modified (auto-release)
# - Manual trigger (workflow_dispatch) with custom release notes
# - Push of version tags (v*)
#
# What it does:
# 1. Scans all plugins for version information
# 2. Generates release notes with plugin versions
# 3. Creates a GitHub Release with the changelog
# 1. Detects plugin version changes compared to the last release
# 2. Generates release notes with updated plugin information
# 3. Creates a GitHub Release with plugin files as downloadable assets
# 4. Supports multiple plugin updates in a single release
name: Plugin Release / 插件发布
on:
# Auto-trigger on push to main when plugins are modified
push:
branches:
- main
paths:
- 'plugins/**/*.py'
tags:
- 'v*'
# Manual trigger with inputs
# 手动触发并提供输入
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., v1.0.0)'
required: true
description: 'Release version (e.g., v1.0.0). Leave empty for auto-generated version.'
required: false
type: string
release_title:
description: 'Release title (optional)'
@@ -38,17 +48,102 @@ on:
type: boolean
default: false
# Trigger on version tags
# 版本标签触发
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
check-changes:
runs-on: ubuntu-latest
outputs:
has_changes: ${{ steps.detect.outputs.has_changes }}
changed_plugins: ${{ steps.detect.outputs.changed_plugins }}
release_notes: ${{ steps.detect.outputs.release_notes }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Detect plugin changes
id: detect
run: |
# Get the last release tag
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "No previous release found, treating all plugins as new"
COMPARE_REF="$(git rev-list --max-parents=0 HEAD)"
else
echo "Comparing with last release: $LAST_TAG"
COMPARE_REF="$LAST_TAG"
fi
# Get current plugin versions
python scripts/extract_plugin_versions.py --json --output current_versions.json
# Get previous plugin versions by checking out old plugins
if git worktree add /tmp/old_repo ${COMPARE_REF} 2>/dev/null; then
if [ -d /tmp/old_repo/plugins ]; then
python scripts/extract_plugin_versions.py --plugins-dir /tmp/old_repo/plugins --json --output old_versions.json
else
echo "[]" > old_versions.json
fi
git worktree remove /tmp/old_repo 2>/dev/null || true
else
echo "Failed to create worktree, using empty version list"
echo "[]" > old_versions.json
fi
# Compare versions and generate release notes
python scripts/extract_plugin_versions.py --compare old_versions.json --output changes.md
python scripts/extract_plugin_versions.py --compare old_versions.json --json --output changes.json
echo "=== Version Changes ==="
cat changes.md
# Check if there are any changes
if grep -q "No changes detected" changes.md; then
echo "has_changes=false" >> $GITHUB_OUTPUT
echo "changed_plugins=" >> $GITHUB_OUTPUT
else
echo "has_changes=true" >> $GITHUB_OUTPUT
# Extract changed plugin file paths using Python
python3 -c "
import json
with open('changes.json', 'r') as f:
data = json.load(f)
files = []
for plugin in data.get('added', []):
if 'file_path' in plugin:
files.append(plugin['file_path'])
for update in data.get('updated', []):
if 'current' in update and 'file_path' in update['current']:
files.append(update['current']['file_path'])
print('\n'.join(files))
" > changed_files.txt
echo "changed_plugins<<EOF" >> $GITHUB_OUTPUT
cat changed_files.txt >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
fi
# Store release notes
{
echo 'release_notes<<EOF'
cat changes.md
echo 'EOF'
} >> $GITHUB_OUTPUT
release:
needs: check-changes
if: needs.check-changes.outputs.has_changes == 'true' || github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
@@ -65,10 +160,13 @@ jobs:
- name: Determine version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then
VERSION="${{ github.event.inputs.version }}"
else
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
else
# Auto-generate version based on date and run number
VERSION="v$(date +'%Y.%m.%d')-${{ github.run_number }}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Release version: $VERSION"
@@ -76,61 +174,133 @@ jobs:
- name: Extract plugin versions
id: plugins
run: |
# Run the version extraction script
python scripts/extract_plugin_versions.py --json --output plugin_versions.json
python scripts/extract_plugin_versions.py --markdown --output plugin_table.md
# Output for debugging
echo "=== Plugin Versions (JSON) ==="
cat plugin_versions.json
echo ""
echo "=== Plugin Versions (Markdown) ==="
echo "=== Plugin Versions ==="
cat plugin_table.md
- name: Collect plugin files for release
id: collect_files
run: |
mkdir -p release_plugins
CHANGED_PLUGINS="${{ needs.check-changes.outputs.changed_plugins }}"
if [ -n "$CHANGED_PLUGINS" ]; then
echo "Collecting changed plugin files..."
echo "$CHANGED_PLUGINS" | while read -r file; do
if [ -n "$file" ] && [ -f "$file" ]; then
dir=$(dirname "$file")
mkdir -p "release_plugins/$dir"
cp "$file" "release_plugins/$file"
echo "Added: $file"
fi
done
else
echo "Collecting all plugin files..."
find plugins -name "*.py" -type f ! -name "__*" | while read -r file; do
dir=$(dirname "$file")
mkdir -p "release_plugins/$dir"
cp "$file" "release_plugins/$file"
done
fi
# Create a zip file with error handling
cd release_plugins
if [ -n "$(ls -A . 2>/dev/null)" ]; then
if zip -r ../plugins_release.zip .; then
echo "Successfully created plugins_release.zip"
else
echo "Warning: Failed to create zip file, creating empty placeholder"
touch ../plugins_release.zip
fi
else
echo "No plugin files to zip, creating empty placeholder"
touch ../plugins_release.zip
fi
cd ..
echo "=== Collected Files ==="
find release_plugins -name "*.py" -type f | head -20
- name: Get commit messages
id: commits
if: github.event_name == 'push'
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$LAST_TAG" ]; then
COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"- %s" --no-merges -- plugins/ | head -20)
else
COMMITS=$(git log --pretty=format:"- %s" --no-merges -10 -- plugins/)
fi
{
echo 'commits<<EOF'
echo "$COMMITS"
echo 'EOF'
} >> $GITHUB_OUTPUT
- name: Generate release notes
id: notes
run: |
VERSION="${{ steps.version.outputs.version }}"
TITLE="${{ github.event.inputs.release_title }}"
NOTES="${{ github.event.inputs.release_notes }}"
DETECTED_CHANGES="${{ needs.check-changes.outputs.release_notes }}"
COMMITS="${{ steps.commits.outputs.commits }}"
# Generate release notes header with version
echo "# ${VERSION} Release / 发布" > release_notes.md
echo "" >> release_notes.md
# Add custom title if provided
if [ -n "$TITLE" ]; then
echo "## $TITLE" >> release_notes.md
echo "" >> release_notes.md
fi
# Add custom notes if provided
if [ -n "$DETECTED_CHANGES" ] && ! echo "$DETECTED_CHANGES" | grep -q "No changes detected"; then
echo "## What's Changed / 更新内容" >> release_notes.md
echo "" >> release_notes.md
echo "$DETECTED_CHANGES" >> release_notes.md
echo "" >> release_notes.md
fi
if [ -n "$COMMITS" ]; then
echo "## Commits / 提交记录" >> release_notes.md
echo "" >> release_notes.md
echo "$COMMITS" >> release_notes.md
echo "" >> release_notes.md
fi
if [ -n "$NOTES" ]; then
echo "## Release Notes / 发布说明" >> release_notes.md
echo "## Additional Notes / 附加说明" >> release_notes.md
echo "" >> release_notes.md
echo "$NOTES" >> release_notes.md
echo "" >> release_notes.md
fi
# Add plugin versions table
echo "## Plugin Versions / 插件版本" >> release_notes.md
echo "## All Plugin Versions / 所有插件版本" >> release_notes.md
echo "" >> release_notes.md
cat plugin_table.md >> release_notes.md
echo "" >> release_notes.md
# Add installation instructions
cat >> release_notes.md << 'INSTALL_INSTRUCTIONS'
cat >> release_notes.md << 'EOF'
## Installation / 安装
## Download / 下载
### From OpenWebUI Community
📦 **plugins_release.zip** - 包含本次更新的所有插件文件 / Contains all updated plugin files
### Installation / 安装
#### From OpenWebUI Community
1. Open OpenWebUI Admin Panel
2. Navigate to Functions/Tools
3. Search for the plugin name
4. Click Install
### Manual Installation / 手动安装
1. Download the plugin file (`.py`)
#### Manual Installation / 手动安装
1. Download the plugin file (`.py`) from the assets below
2. Open OpenWebUI Admin Panel → Functions
3. Click "Create Function" → Import
4. Paste the plugin code
@@ -139,8 +309,7 @@ jobs:
📚 [Documentation / 文档](https://fu-jie.github.io/awesome-openwebui/)
🐛 [Report Issues / 报告问题](https://github.com/Fu-Jie/awesome-openwebui/issues)
INSTALL_INSTRUCTIONS
EOF
echo "=== Release Notes ==="
cat release_notes.md
@@ -154,6 +323,7 @@ jobs:
prerelease: ${{ github.event.inputs.prerelease || false }}
files: |
plugin_versions.json
plugins_release.zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -163,5 +333,8 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Plugin Versions" >> $GITHUB_STEP_SUMMARY
echo "### Updated Plugins" >> $GITHUB_STEP_SUMMARY
echo "${{ needs.check-changes.outputs.release_notes }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### All Plugin Versions" >> $GITHUB_STEP_SUMMARY
cat plugin_table.md >> $GITHUB_STEP_SUMMARY