Skip to content

fix:修复IEC61850客户端无法解析服务端主动报告的bug #16

fix:修复IEC61850客户端无法解析服务端主动报告的bug

fix:修复IEC61850客户端无法解析服务端主动报告的bug #16

Workflow file for this run

name: Build Windows
on:
push:
tags:
- "v*"
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: windows-2022
timeout-minutes: 120
outputs:
release_tag: ${{ steps.version.outputs.release_tag }}
release_version: ${{ steps.version.outputs.release_version }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Prepare release version from tag
id: version
shell: pwsh
run: |
if ("${{ github.ref_type }}" -ne "tag") {
Write-Error "This release workflow must be triggered by a version tag, for example v1.4.1."
exit 1
}
$tag = "${{ github.ref_name }}".Trim()
if ($tag -notmatch '^v\d+\.\d+\.\d+$') {
Write-Error "Release tag must match vMAJOR.MINOR.PATCH, for example v1.4.1. Got: $tag"
exit 1
}
$version = $tag.Substring(1)
"release_version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
"release_tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
Write-Host "Release tag: $tag"
Write-Host "Release version: $version"
- name: Sync release version to build metadata
shell: pwsh
run: |
$version = "${{ steps.version.outputs.release_version }}"
$path = "pyproject.toml"
$content = Get-Content -Path $path -Raw -Encoding UTF8
$pattern = '(?m)^version\s*=\s*"[^"]+"'
if (-not [regex]::IsMatch($content, $pattern)) {
Write-Error "Cannot find version line in pyproject.toml"
exit 1
}
$newContent = [regex]::Replace($content, $pattern, "version = `"$version`"", 1)
Set-Content -Path $path -Value $newContent -Encoding UTF8
python scripts/sync_version.py
if ($LASTEXITCODE -ne 0) {
Write-Error "Version sync failed"
exit 1
}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Install Python build dependencies
run: uv sync --extra build
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri -> src-tauri/target
- name: Install frontend dependencies
working-directory: front
run: npm ci
- name: Build Windows application (Tauri + Sidecar)
shell: pwsh
run: |
.venv\Scripts\Activate.ps1
.\scripts\build_tauri_windows.ps1
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ems-simulate-windows-${{ steps.version.outputs.release_tag }}
path: |
src-tauri/target/release/ems-simulate.exe
src-tauri/target/release/bundle/
compression-level: 0
if-no-files-found: error
release:
runs-on: ubuntu-latest
needs: build
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate changelog
id: changelog
shell: bash
run: |
set -euo pipefail
current_tag="${{ needs.build.outputs.release_tag }}"
git fetch --tags --force
previous_tag="$(git tag --sort=-version:refname | grep -E '^v[0-9]+(\.[0-9]+){1,2}$' | grep -vFx "$current_tag" | head -n 1 || true)"
if [ -n "$previous_tag" ]; then
commit_range="${previous_tag}..${GITHUB_SHA}"
range_label="Changes since ${previous_tag}"
else
commit_range="${GITHUB_SHA}"
range_label="Initial release"
fi
workdir="$(mktemp -d)"
trap 'rm -rf "$workdir"' EXIT
for section in breaking feat fix perf refactor docs build ci test chore other; do
: > "$workdir/$section.md"
done
cc_header_re='^[A-Za-z]+(\([^)]+\))?(!)?[::][[:space:]]*.+$'
cc_full_re='^([A-Za-z]+)(\(([^)]+)\))?(!)?[::][[:space:]]*(.+)$'
trim() {
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' <<< "$1"
}
escape_md() {
local value="$1"
value="${value//\`/\\\`}"
printf '%s' "$value"
}
clean_line() {
local value
value="$(trim "$1")"
value="$(sed -E 's/^```[[:alnum:]_-]*[[:space:]]*//' <<< "$value")"
value="$(sed -E 's/[[:space:]]*```$//' <<< "$value")"
value="$(sed -E 's/^([-*+]|[0-9]+\.)[[:space:]]+//' <<< "$value")"
trim "$value"
}
format_body() {
local body="$1"
local line cleaned
while IFS= read -r line; do
cleaned="$(clean_line "$line")"
[ -z "$cleaned" ] && continue
[[ "$cleaned" == \`\`\`* ]] && continue
printf ' - %s\n' "$(escape_md "$cleaned")"
done <<< "$body"
}
write_entry() {
local file="$1"
local scope="$2"
local description="$3"
local short_sha="$4"
local body="$5"
if [ -n "$scope" ]; then
printf -- '- **%s**: %s (`%s`)\n' "$(escape_md "$scope")" "$(escape_md "$description")" "$short_sha" >> "$file"
else
printf -- '- %s (`%s`)\n' "$(escape_md "$description")" "$short_sha" >> "$file"
fi
format_body "$body" >> "$file"
}
parse_commit() {
local short_sha="$1"
local subject="$2"
local body="$3"
local parsed_subject type scope description bang target_file promoted line remaining_body
parsed_subject="$(clean_line "$subject")"
remaining_body="$body"
if ! [[ "$parsed_subject" =~ $cc_header_re ]]; then
promoted=""
remaining_body=""
while IFS= read -r line; do
line="$(clean_line "$line")"
[ -z "$line" ] && continue
if [ -z "$promoted" ] && [[ "$line" =~ $cc_header_re ]]; then
promoted="$line"
continue
fi
remaining_body+="$line"$'\n'
done <<< "$body"
if [ -n "$promoted" ]; then
parsed_subject="$promoted"
fi
fi
if [[ "$parsed_subject" =~ $cc_full_re ]]; then
type="$(tr '[:upper:]' '[:lower:]' <<< "${BASH_REMATCH[1]}")"
scope="${BASH_REMATCH[3]:-}"
bang="${BASH_REMATCH[4]:-}"
description="${BASH_REMATCH[5]}"
case "$type" in
feat) target_file="$workdir/feat.md" ;;
fix) target_file="$workdir/fix.md" ;;
perf) target_file="$workdir/perf.md" ;;
refactor) target_file="$workdir/refactor.md" ;;
docs) target_file="$workdir/docs.md" ;;
build) target_file="$workdir/build.md" ;;
ci) target_file="$workdir/ci.md" ;;
test) target_file="$workdir/test.md" ;;
chore|style) target_file="$workdir/chore.md" ;;
*) target_file="$workdir/other.md" ;;
esac
if [ "$bang" = "!" ] || grep -qiE '^BREAKING CHANGE:' <<< "$remaining_body"; then
write_entry "$workdir/breaking.md" "$scope" "$description" "$short_sha" "$remaining_body"
else
write_entry "$target_file" "$scope" "$description" "$short_sha" "$remaining_body"
fi
else
parsed_subject="$(clean_line "$subject")"
[ -z "$parsed_subject" ] && parsed_subject="No subject"
write_entry "$workdir/other.md" "" "$parsed_subject" "$short_sha" "$body"
fi
}
while IFS= read -r -d $'\x1e' record; do
[ -z "$record" ] && continue
sha="${record%%$'\x1f'*}"
rest="${record#*$'\x1f'}"
short_sha="${rest%%$'\x1f'*}"
rest="${rest#*$'\x1f'}"
subject="${rest%%$'\x1f'*}"
body="${rest#*$'\x1f'}"
parse_commit "$short_sha" "$subject" "$body"
done < <(git log "$commit_range" --no-merges --pretty=format:'%H%x1f%h%x1f%s%x1f%b%x1e')
notes_file="release-notes.md"
{
printf '## %s\n\n' "$current_tag"
printf '%s.\n\n' "$range_label"
} > "$notes_file"
add_section() {
local file="$1"
local title="$2"
if [ -s "$file" ]; then
printf '### %s\n\n' "$title" >> "$notes_file"
cat "$file" >> "$notes_file"
printf '\n' >> "$notes_file"
fi
}
add_section "$workdir/breaking.md" "💥 Breaking Changes"
add_section "$workdir/feat.md" "✨ 新功能"
add_section "$workdir/fix.md" "🐛 Bug 修复"
add_section "$workdir/perf.md" "⚡ 性能优化"
add_section "$workdir/refactor.md" "♻️ 代码重构"
add_section "$workdir/docs.md" "📝 文档更新"
add_section "$workdir/build.md" "📦 构建相关"
add_section "$workdir/ci.md" "👷 CI 配置"
add_section "$workdir/test.md" "✅ 测试"
add_section "$workdir/chore.md" "🔧 杂项"
add_section "$workdir/other.md" "其他变更"
if ! grep -q '^### ' "$notes_file"; then
printf 'No commit changes found for this release.\n' >> "$notes_file"
fi
printf 'notes_file=%s\n' "$notes_file" >> "$GITHUB_OUTPUT"
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
pattern: ems-simulate-windows-*
path: release-assets
merge-multiple: true
- name: Delete existing release (if any) to avoid stale assets
uses: actions/github-script@v7
with:
script: |
const tag = '${{ needs.build.outputs.release_tag }}';
try {
const { data: release } = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: tag,
});
if (release) {
// Delete all existing assets first
for (const asset of release.assets) {
await github.rest.repos.deleteReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
asset_id: asset.id,
});
console.log(`Deleted asset: ${asset.name}`);
}
// Delete the release itself
await github.rest.repos.deleteRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id,
});
console.log(`Deleted existing release: ${tag}`);
}
} catch (err) {
if (err.status === 404) {
console.log(`No existing release found for tag: ${tag}`);
} else {
throw err;
}
}
- name: Publish GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.build.outputs.release_tag }}
name: EMS Simulate ${{ needs.build.outputs.release_tag }}
target_commitish: ${{ github.sha }}
draft: false
prerelease: false
make_latest: true
body_path: ${{ steps.changelog.outputs.notes_file }}
files: release-assets/*.msi
fail_on_unmatched_files: true
generate_release_notes: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}