Nightly Build #596
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "Nightly Build" | |
| on: | |
| schedule: | |
| # 每天 UTC 4 点执行,即北京时间 12 点 | |
| - cron: "0 4 * * *" | |
| workflow_dispatch: # 允许手动触发 | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| check-nightly-conditions: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_build: ${{ steps.check.outputs.should_build }} | |
| has_nightly: ${{ steps.check.outputs.has_nightly }} | |
| latest_commit: ${{ steps.check.outputs.latest_commit }} | |
| labeled_commits: ${{ steps.check.outputs.labeled_commits }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check nightly build conditions | |
| id: check | |
| run: | | |
| echo "Checking nightly build conditions..." | |
| # 检查commit是否有labels | |
| has_labels() { | |
| local commit_sha=$1 | |
| # 获取commit的PR信息,检查是否有labels | |
| local pr_number=$(gh pr list --state merged --search "$commit_sha" --json number --jq '.[0].number' 2>/dev/null || echo "") | |
| if [ -n "$pr_number" ]; then | |
| local labels=$(gh pr view "$pr_number" --json labels --jq '.labels | length' 2>/dev/null || echo "0") | |
| [ "$labels" -gt 0 ] | |
| else | |
| # 如果不是PR commit,检查commit message是否包含标签格式 | |
| git log --format=%B -n 1 "$commit_sha" | grep -E '\[(feat|fix|style|refactor|perf|test)\]' >/dev/null 2>&1 | |
| fi | |
| } | |
| # 获取有labels的commits | |
| get_labeled_commits_since() { | |
| local since_commit=$1 | |
| local commits=$(git rev-list --reverse "$since_commit"..HEAD 2>/dev/null || git rev-list --reverse HEAD) | |
| local labeled_commits="" | |
| for commit in $commits; do | |
| if has_labels "$commit"; then | |
| if [ -z "$labeled_commits" ]; then | |
| labeled_commits="$commit" | |
| else | |
| labeled_commits="$labeled_commits $commit" | |
| fi | |
| fi | |
| done | |
| echo "$labeled_commits" | |
| } | |
| # 检查是否存在nightly prerelease | |
| if gh release view nightly >/dev/null 2>&1; then | |
| echo "has_nightly=true" >> $GITHUB_OUTPUT | |
| echo "Found existing nightly release" | |
| # 获取nightly标签的commit | |
| nightly_commit=$(git rev-list -n 1 nightly 2>/dev/null || echo "") | |
| if [ -n "$nightly_commit" ]; then | |
| # 检查nightly标签之后是否有带labels的新commit | |
| labeled_commits=$(get_labeled_commits_since "$nightly_commit") | |
| latest_commit=$(git rev-parse HEAD) | |
| echo "latest_commit=$latest_commit" >> $GITHUB_OUTPUT | |
| if [ -n "$labeled_commits" ]; then | |
| echo "New labeled commits found after nightly tag: $labeled_commits" | |
| echo "labeled_commits=$labeled_commits" >> $GITHUB_OUTPUT | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "No new labeled commits after nightly tag" | |
| echo "should_build=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "Nightly tag not found, will build" | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "has_nightly=false" >> $GITHUB_OUTPUT | |
| echo "No nightly release found" | |
| # 获取最新的正式release | |
| latest_release=$(gh release list --exclude-pre-releases --limit 1 --json tagName --jq '.[0].tagName' 2>/dev/null || echo "") | |
| if [ -n "$latest_release" ]; then | |
| # 检查最新release之后是否有带labels的新commit | |
| release_commit=$(git rev-list -n 1 "$latest_release" 2>/dev/null || echo "") | |
| labeled_commits=$(get_labeled_commits_since "$release_commit") | |
| latest_commit=$(git rev-parse HEAD) | |
| echo "latest_commit=$latest_commit" >> $GITHUB_OUTPUT | |
| if [ -n "$labeled_commits" ]; then | |
| echo "New labeled commits found after latest release $latest_release: $labeled_commits" | |
| echo "labeled_commits=$labeled_commits" >> $GITHUB_OUTPUT | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "No new labeled commits after latest release" | |
| echo "should_build=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "No previous releases found, checking for any labeled commits" | |
| labeled_commits=$(get_labeled_commits_since "") | |
| latest_commit=$(git rev-parse HEAD) | |
| echo "latest_commit=$latest_commit" >> $GITHUB_OUTPUT | |
| if [ -n "$labeled_commits" ]; then | |
| echo "Found labeled commits, will build nightly: $labeled_commits" | |
| echo "labeled_commits=$labeled_commits" >> $GITHUB_OUTPUT | |
| echo "should_build=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "No labeled commits found, skipping nightly build" | |
| echo "should_build=false" >> $GITHUB_OUTPUT | |
| fi | |
| fi | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| delete-existing-nightly: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| needs: check-nightly-conditions | |
| if: needs.check-nightly-conditions.outputs.should_build == 'true' && needs.check-nightly-conditions.outputs.has_nightly == 'true' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Delete existing nightly release and tag | |
| run: | | |
| echo "Deleting existing nightly release and tag..." | |
| gh release delete nightly --cleanup-tag --yes | |
| echo "Nightly release and tag deleted successfully" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| create-nightly-release: | |
| permissions: | |
| contents: write | |
| runs-on: ubuntu-latest | |
| needs: [check-nightly-conditions, delete-existing-nightly] | |
| if: always() && needs.check-nightly-conditions.outputs.should_build == 'true' && needs.delete-existing-nightly.result != 'failure' | |
| outputs: | |
| release_id: ${{ steps.create-release.outputs.result }} | |
| build_date: ${{ steps.date.outputs.date }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get current date | |
| id: date | |
| run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT | |
| - name: Generate changelog from labeled commits | |
| id: changelog | |
| run: | | |
| labeled_commits="${{ needs.check-nightly-conditions.outputs.labeled_commits }}" | |
| if [ -z "$labeled_commits" ]; then | |
| echo "changelog=- No labeled commits found" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # 使用关联数组来跟踪已处理的PR编号和直接提交 | |
| declare -A seen_prs | |
| declare -A seen_commits | |
| changelog="" | |
| for commit in $labeled_commits; do | |
| # 尝试获取PR信息 | |
| pr_info=$(gh pr list --state merged --search "$commit" --json number,title --jq '.[0] | select(.number != null)' 2>/dev/null || echo "") | |
| if [ -n "$pr_info" ]; then | |
| # 如果是PR commit,使用PR编号去重 | |
| pr_number=$(echo "$pr_info" | jq -r '.number') | |
| # 检查是否已经处理过这个PR | |
| if [ -z "${seen_prs[$pr_number]}" ]; then | |
| pr_title=$(echo "$pr_info" | jq -r '.title') | |
| changelog="${changelog}- ${pr_title} (#${pr_number})\n" | |
| seen_prs[$pr_number]=1 | |
| fi | |
| else | |
| # 如果不是PR commit,使用commit hash去重 | |
| if [ -z "${seen_commits[$commit]}" ]; then | |
| commit_title=$(git log --format=%s -n 1 "$commit") | |
| commit_short=$(echo "$commit" | cut -c1-7) | |
| changelog="${changelog}- ${commit_title} (${commit_short})\n" | |
| seen_commits[$commit]=1 | |
| fi | |
| fi | |
| done | |
| # 使用EOF来处理多行输出 | |
| { | |
| echo 'changelog<<EOF' | |
| echo -e "$changelog" | |
| echo 'EOF' | |
| } >> $GITHUB_OUTPUT | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create nightly release | |
| id: create-release | |
| uses: actions/github-script@v7 | |
| with: | |
| retries: 3 | |
| script: | | |
| const buildDate = '${{ steps.date.outputs.date }}'; | |
| const commitSha = '${{ needs.check-nightly-conditions.outputs.latest_commit }}'.substring(0, 7); | |
| const changelog = `${{ steps.changelog.outputs.changelog }}`; | |
| const { data } = await github.rest.repos.createRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| tag_name: 'nightly', | |
| name: `Nightly Build ${buildDate}`, | |
| body: `🌙 **Nightly Build**\n\n` + | |
| `**Build Date:** ${buildDate}\n` + | |
| `**Commit:** ${commitSha}\n\n` + | |
| `## 📝 Changes\n\n${changelog}\n` + | |
| `⚠️ This is a nightly build and may contain unstable features. Use at your own risk.\n\n` + | |
| `For stable releases, please check the [releases page](https://github.com/${context.repo.owner}/${context.repo.repo}/releases).`, | |
| draft: true, | |
| prerelease: true | |
| }); | |
| return data.id; | |
| build-nightly: | |
| needs: create-nightly-release | |
| if: always() && needs.create-nightly-release.result == 'success' | |
| permissions: | |
| contents: write | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: setup node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: lts/* | |
| - uses: oven-sh/setup-bun@v1 | |
| - name: Cache frontend dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.bun | |
| node_modules/ | |
| key: ${{ runner.os }}-frontend-nightly-${{ hashFiles('**/bun.lockb', '**/package.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-frontend-nightly- | |
| ${{ runner.os }}-frontend- | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-pc-windows-msvc | |
| - name: Cache Rust dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/bin/ | |
| ~/.cargo/registry/index/ | |
| ~/.cargo/registry/cache/ | |
| ~/.cargo/git/db/ | |
| target/release/deps | |
| target/release/build | |
| key: ${{ runner.os }}-rust-nightly-${{ hashFiles('**/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-rust-nightly- | |
| ${{ runner.os }}-rust- | |
| - name: install frontend dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Build nightly application | |
| uses: tauri-apps/tauri-action@v0.5.23 | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| releaseId: ${{ needs.create-nightly-release.outputs.release_id }} | |
| releaseBody: | | |
| 🌙 **Nightly Build ${{ needs.create-nightly-release.outputs.build_date }}** | |
| ⚠️ This is a nightly build and may contain unstable features. | |
| args: --config src-tauri/tauri.debug.conf.json | |
| publish-nightly: | |
| permissions: | |
| contents: write | |
| runs-on: ubuntu-latest | |
| needs: [check-nightly-conditions, create-nightly-release, build-nightly] | |
| if: always() && needs.create-nightly-release.result == 'success' | |
| steps: | |
| - name: Publish nightly release | |
| uses: actions/github-script@v7 | |
| env: | |
| release_id: ${{ needs.create-nightly-release.outputs.release_id }} | |
| with: | |
| retries: 3 | |
| script: | | |
| await github.rest.repos.updateRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| release_id: process.env.release_id, | |
| draft: false, | |
| }); | |
| - name: Create nightly summary | |
| run: | | |
| echo "## 🌙 Nightly Build Published Successfully!" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Build Date:** ${{ needs.create-nightly-release.outputs.build_date }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Release ID:** ${{ needs.create-nightly-release.outputs.release_id }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Commit:** ${{ needs.check-nightly-conditions.outputs.latest_commit }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "[View Nightly Release](https://github.com/${{ github.repository }}/releases/tag/nightly)" >> $GITHUB_STEP_SUMMARY | |
| skip-build: | |
| runs-on: ubuntu-latest | |
| needs: check-nightly-conditions | |
| if: needs.check-nightly-conditions.outputs.should_build == 'false' | |
| steps: | |
| - name: Skip nightly build | |
| run: | | |
| echo "## ⏭️ Nightly Build Skipped" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "No new commits found since the last nightly build or release." >> $GITHUB_STEP_SUMMARY | |
| echo "Nightly build is not needed at this time." >> $GITHUB_STEP_SUMMARY |