| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- name: Release Client
- on:
- push:
- tags:
- - 'v*'
- workflow_dispatch:
- inputs:
- tag_name:
- description: '要发布的 tag,例如 v2.0.1'
- required: true
- type: string
- permissions:
- contents: write
- jobs:
- create-release:
- name: Create GitHub Release
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- with:
- fetch-depth: 0
- ref: ${{ inputs.tag_name || github.ref }}
- - name: Create release notes from commits
- env:
- TAG_NAME: ${{ inputs.tag_name || github.ref_name }}
- run: |
- PREVIOUS_TAG="$(git describe --tags --abbrev=0 "${TAG_NAME}^" 2>/dev/null || true)"
- if [ -n "$PREVIOUS_TAG" ]; then
- RANGE="$PREVIOUS_TAG..$TAG_NAME"
- COMPARE_URL="https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${TAG_NAME}"
- else
- RANGE="$TAG_NAME"
- COMPARE_URL="https://github.com/${{ github.repository }}/commits/${TAG_NAME}"
- fi
- {
- echo "## 更新内容"
- echo
- git log "$RANGE" --no-merges --pretty=format:'- %s (%h)' || true
- echo
- echo
- echo "**Full Changelog**: $COMPARE_URL"
- } > release_notes.md
- - name: Create or update GitHub Release
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAG_NAME: ${{ inputs.tag_name || github.ref_name }}
- run: |
- if gh release view "$TAG_NAME" >/dev/null 2>&1; then
- gh release edit "$TAG_NAME" --title "$TAG_NAME" --notes-file release_notes.md
- else
- gh release create "$TAG_NAME" --title "$TAG_NAME" --notes-file release_notes.md
- fi
- build:
- name: Build ${{ matrix.os }}
- needs: create-release
- runs-on: ${{ matrix.os }}
- strategy:
- fail-fast: false
- matrix:
- os: [windows-latest, macos-latest]
- defaults:
- run:
- working-directory: client
- shell: bash
- steps:
- - name: Checkout
- uses: actions/checkout@v4
- with:
- ref: ${{ inputs.tag_name || github.ref }}
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: 22
- cache: npm
- cache-dependency-path: client/package-lock.json
- - name: Cache Electron build downloads
- if: runner.os == 'macOS'
- uses: actions/cache@v4
- with:
- path: |
- ~/Library/Caches/electron
- ~/Library/Caches/electron-builder
- key: ${{ runner.os }}-electron-${{ hashFiles('client/package-lock.json') }}
- restore-keys: |
- ${{ runner.os }}-electron-
- - name: Install dependencies
- run: npm ci
- - name: Install build type dependencies
- run: npm install --no-save @types/plist
- - name: Sync package version from tag
- env:
- TAG_NAME: ${{ inputs.tag_name || github.ref_name }}
- run: |
- VERSION="${TAG_NAME#v}"
- npm version "$VERSION" --no-git-tag-version --allow-same-version
- - name: Generate macOS icon
- if: runner.os == 'macOS'
- run: |
- rm -rf assets/icon.iconset
- mkdir -p assets/icon.iconset
- sips -z 16 16 assets/icon_256.png --out assets/icon.iconset/icon_16x16.png
- sips -z 32 32 assets/icon_256.png --out assets/icon.iconset/icon_16x16@2x.png
- sips -z 32 32 assets/icon_256.png --out assets/icon.iconset/icon_32x32.png
- sips -z 64 64 assets/icon_256.png --out assets/icon.iconset/icon_32x32@2x.png
- sips -z 128 128 assets/icon_256.png --out assets/icon.iconset/icon_128x128.png
- sips -z 256 256 assets/icon_256.png --out assets/icon.iconset/icon_128x128@2x.png
- sips -z 256 256 assets/icon_256.png --out assets/icon.iconset/icon_256x256.png
- sips -z 512 512 assets/icon_256.png --out assets/icon.iconset/icon_256x256@2x.png
- sips -z 512 512 assets/icon_256.png --out assets/icon.iconset/icon_512x512.png
- sips -z 1024 1024 assets/icon_256.png --out assets/icon.iconset/icon_512x512@2x.png
- iconutil -c icns assets/icon.iconset -o assets/icon.icns
- - name: Build renderer
- run: npm run build
- - name: Preload Electron macOS runtimes
- if: runner.os == 'macOS'
- run: |
- export ELECTRON_CACHE="$HOME/Library/Caches/electron"
- ELECTRON_VERSION="$(node -p "require('./node_modules/electron/package.json').version")"
- cache_dir="$ELECTRON_CACHE"
- mkdir -p "$cache_dir"
- for arch in x64 arm64; do
- file="$cache_dir/electron-v${ELECTRON_VERSION}-darwin-${arch}.zip"
- if [ -f "$file" ] && unzip -tq "$file" >/dev/null 2>&1; then
- echo "Electron ${ELECTRON_VERSION} darwin-${arch} already cached."
- continue
- fi
- tmp="${file}.tmp"
- rm -f "$file" "$tmp"
- curl --fail --location --retry 5 --retry-all-errors --retry-delay 10 \
- "https://github.com/electron/electron/releases/download/v${ELECTRON_VERSION}/electron-v${ELECTRON_VERSION}-darwin-${arch}.zip" \
- --output "$tmp"
- unzip -tq "$tmp" >/dev/null
- mv "$tmp" "$file"
- done
- - name: Build Windows NSIS and ZIP artifacts
- if: runner.os == 'Windows'
- run: npx electron-builder --win nsis zip --publish never
- - name: Build Windows MSI artifact
- if: runner.os == 'Windows'
- run: npx electron-builder --win msi --publish never -c.productName=OpenBidKit_Yibiao -c.extraMetadata.author=mark -c.copyright="Copyright (c) 2026 mark"
- - name: Build and publish macOS artifacts
- if: runner.os == 'macOS'
- run: |
- export ELECTRON_CACHE="$HOME/Library/Caches/electron"
- export ELECTRON_BUILDER_CACHE="$HOME/Library/Caches/electron-builder"
- for attempt in 1 2 3; do
- echo "Build macOS artifacts, attempt ${attempt}/3."
- if npx electron-builder --mac --publish never; then
- exit 0
- fi
- if [ "$attempt" -eq 3 ]; then
- exit 1
- fi
- sleep $((attempt * 20))
- done
- - name: Package macOS DMG with instructions
- if: runner.os == 'macOS'
- run: |
- shopt -s nullglob
- for dmg in release/*.dmg; do
- base="$(basename "$dmg" .dmg)"
- package_dir="release/${base}-package"
- rm -rf "$package_dir"
- mkdir -p "$package_dir"
- cp "$dmg" "$package_dir/"
- cat > "$package_dir/macOS使用说明.txt" <<'EOF'
- macOS 使用说明
- 如果双击 App 提示“已损坏,无法打开”或“无法验证开发者”,这是因为本软件未进行 Apple 官方签名和公证,并不代表文件真的损坏。
- 使用步骤:
- 1. 双击 dmg 文件。
- 2. 将“易标投标工具箱.app”拖到“应用程序”文件夹。
- 3. 打开“终端”App。
- 4. 执行下面命令:
- xattr -dr com.apple.quarantine /Applications/易标投标工具箱.app
- 5. 再从“应用程序”中打开“易标投标工具箱”。
- 如果仍无法打开,请右键点击 App,选择“打开”,再确认打开。
- EOF
- (cd release && ditto -c -k --sequesterRsrc --keepParent "$(basename "$package_dir")" "${base}-package.zip")
- rm -rf "$package_dir"
- rm -f "$dmg"
- done
- - name: Upload release assets
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- TAG_NAME: ${{ inputs.tag_name || github.ref_name }}
- run: |
- shopt -s nullglob
- files=(release/*.exe release/*.msi release/*.zip release/*.blockmap release/latest*.yml)
- if [ ${#files[@]} -eq 0 ]; then
- echo "No release assets found."
- exit 1
- fi
- gh release upload "$TAG_NAME" "${files[@]}" --clobber
|