Skip to content

Nightly Build

Nightly Build #1059

Workflow file for this run

name: Nightly Build
on:
push:
paths:
- '.github/workflows/nightly.yml'
schedule:
# 每小时检测一次上游更新 (改为每小时的第 16 分钟,避开整点高峰期)
- cron: '16 * * * *'
workflow_dispatch:
inputs:
force_build:
description: '强制构建(跳过 commit 数量检测)'
required: false
type: boolean
default: false
min_commits:
description: '触发构建的最小 commit 数量'
required: false
type: number
default: 5
permissions:
contents: write
env:
UPSTREAM_REPO: anomalyco/opencode
UPSTREAM_BRANCH: dev
MIN_COMMITS_THRESHOLD: 5 # 累计超过此数量才触发构建
jobs:
check-upstream:
name: Check Upstream Updates
runs-on: ubuntu-latest
outputs:
should_build: ${{ steps.check.outputs.should_build }}
upstream_sha: ${{ steps.check.outputs.upstream_sha }}
upstream_date: ${{ steps.check.outputs.upstream_date }}
commit_count: ${{ steps.check.outputs.commit_count }}
changelog: ${{ steps.check.outputs.changelog }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for upstream updates
id: check
run: |
echo "=== Checking upstream updates ==="
# 获取上游最新 commit
UPSTREAM_SHA=$(git ls-remote https://github.com/${{ env.UPSTREAM_REPO }}.git refs/heads/${{ env.UPSTREAM_BRANCH }} | cut -f1)
echo "Upstream SHA: $UPSTREAM_SHA"
# 获取当前日期(CST)
UPSTREAM_DATE=$(TZ='Asia/Shanghai' date +"%Y%m%d-%H%M")
echo "Build timestamp: $UPSTREAM_DATE"
# 读取上次构建的 commit SHA
LAST_SHA=""
if [ -f ".nightly-state" ]; then
LAST_SHA=$(cat .nightly-state | head -1)
echo "Last built SHA: $LAST_SHA"
else
echo "No previous build state found"
fi
# 获取 commit 数量阈值
MIN_COMMITS=${{ github.event.inputs.min_commits || env.MIN_COMMITS_THRESHOLD }}
echo "Min commits threshold: $MIN_COMMITS"
# 判断是否需要构建
SHOULD_BUILD="false"
COMMIT_COUNT=0
CHANGELOG=""
if [ "${{ github.event.inputs.force_build }}" == "true" ]; then
echo "Force build requested"
SHOULD_BUILD="true"
elif [ -z "$LAST_SHA" ]; then
echo "First nightly build"
SHOULD_BUILD="true"
elif [ "$UPSTREAM_SHA" != "$LAST_SHA" ]; then
echo "Upstream has new commits, calculating diff..."
# Clone 上游仓库获取详细信息
git clone --depth 200 --branch ${{ env.UPSTREAM_BRANCH }} https://github.com/${{ env.UPSTREAM_REPO }}.git /tmp/upstream 2>/dev/null || true
if [ -d "/tmp/upstream" ]; then
cd /tmp/upstream
# 计算 commit 差异数量
COMMIT_COUNT=$(git rev-list --count $LAST_SHA..$UPSTREAM_SHA 2>/dev/null || echo "0")
echo "New commits since last build: $COMMIT_COUNT"
# 判断是否达到阈值
if [ "$COMMIT_COUNT" -ge "$MIN_COMMITS" ]; then
echo "Commit count ($COMMIT_COUNT) >= threshold ($MIN_COMMITS), triggering build"
SHOULD_BUILD="true"
# 生成 changelog (最多 50 条)
CHANGELOG=$(git log $LAST_SHA..$UPSTREAM_SHA --format="- %s (\`%h\`)" | head -50)
else
echo "Commit count ($COMMIT_COUNT) < threshold ($MIN_COMMITS), skipping build"
fi
cd -
else
echo "Failed to clone upstream, triggering build anyway"
SHOULD_BUILD="true"
fi
else
echo "No updates detected (SHA unchanged)"
fi
# 如果强制构建但没有 changelog,生成最近的 changelog
if [ "$SHOULD_BUILD" == "true" ] && [ -z "$CHANGELOG" ] && [ -d "/tmp/upstream" ]; then
cd /tmp/upstream
CHANGELOG=$(git log -20 --format="- %s (\`%h\`)")
cd -
fi
echo "should_build=$SHOULD_BUILD" >> $GITHUB_OUTPUT
echo "upstream_sha=$UPSTREAM_SHA" >> $GITHUB_OUTPUT
echo "upstream_date=$UPSTREAM_DATE" >> $GITHUB_OUTPUT
echo "commit_count=$COMMIT_COUNT" >> $GITHUB_OUTPUT
# Changelog 可能很长,使用多行输出
echo "changelog<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "=== Check complete ==="
echo "Should build: $SHOULD_BUILD"
build-cli:
name: Build CLI Tool
runs-on: ubuntu-latest
needs: check-upstream
if: needs.check-upstream.outputs.should_build == 'true'
strategy:
matrix:
include:
- os: windows
arch: amd64
ext: .exe
- os: linux
arch: amd64
ext: ""
- os: darwin
arch: arm64
ext: ""
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: cli-go/go.mod
- name: Build CLI
env:
GOOS: ${{ matrix.os }}
GOARCH: ${{ matrix.arch }}
CGO_ENABLED: 0
run: |
cd cli-go
go build -ldflags="-s -w" -o ../dist/opencode-cli-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }} .
- name: Upload CLI Artifact
uses: actions/upload-artifact@v4
with:
name: cli-${{ matrix.os }}-${{ matrix.arch }}
path: dist/*
build-opencode:
name: Build OpenCode Chinese
runs-on: ubuntu-latest
needs: [check-upstream, build-cli]
if: needs.check-upstream.outputs.should_build == 'true'
strategy:
matrix:
include:
- platform: windows-x64
bun_target: bun-windows-x64
- platform: linux-x64
bun_target: bun-linux-x64
- platform: linux-arm64
bun_target: bun-linux-aarch64
- platform: darwin-x64
bun_target: bun-darwin-x64
- platform: darwin-arm64
bun_target: bun-darwin-arm64
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: cli-go/go.mod
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.8'
- name: Build CLI for current platform
run: |
cd cli-go
go build -o ../opencode-cli .
- name: Clone OpenCode source
run: |
git clone --depth 1 --branch ${{ env.UPSTREAM_BRANCH }} https://github.com/${{ env.UPSTREAM_REPO }}.git opencode-zh-CN
- name: Apply Chinese translation
env:
OPENCODE_SOURCE_DIR: ${{ github.workspace }}/opencode-zh-CN
run: |
./opencode-cli apply
- name: Build OpenCode
env:
OPENCODE_SOURCE_DIR: ${{ github.workspace }}/opencode-zh-CN
run: |
echo "=== Build Environment ==="
echo "Platform: ${{ matrix.platform }}"
echo "OPENCODE_SOURCE_DIR: $OPENCODE_SOURCE_DIR"
echo "Bun version: $(bun --version)"
echo ""
echo "=== Upstream repo structure ==="
ls -la opencode-zh-CN/ || true
ls -la opencode-zh-CN/packages/ || true
echo ""
echo "=== Starting build ==="
./opencode-cli build --platform ${{ matrix.platform }} --deploy=false
echo ""
echo "=== Post-build: dist directory ==="
find opencode-zh-CN/packages/opencode/dist -type f 2>/dev/null | head -30 || echo "dist directory not found"
- name: Package
env:
NIGHTLY_DATE: ${{ needs.check-upstream.outputs.upstream_date }}
run: |
VERSION="nightly"
PLATFORM=${{ matrix.platform }}
PACKAGE_NAME="opencode-zh-CN-${VERSION}-${PLATFORM}"
echo "=== Packaging ${PACKAGE_NAME} ==="
BUILD_DIR="opencode-zh-CN/packages/opencode/dist/opencode-${PLATFORM}/bin"
echo "Looking for build artifacts in: ${BUILD_DIR}"
ls -la ${BUILD_DIR}/ || echo "Build dir not found"
mkdir -p dist
if [ "$PLATFORM" == "windows-x64" ]; then
BINARY="${BUILD_DIR}/opencode.exe"
else
BINARY="${BUILD_DIR}/opencode"
fi
if [ -f "$BINARY" ]; then
zip -j dist/${PACKAGE_NAME}.zip "$BINARY"
echo "✓ Created dist/${PACKAGE_NAME}.zip"
ls -la dist/
else
echo "❌ Binary not found: $BINARY"
find opencode-zh-CN -name "opencode*" -type f 2>/dev/null | head -20
exit 1
fi
- name: Upload OpenCode Artifact
uses: actions/upload-artifact@v4
with:
name: opencode-${{ matrix.platform }}
path: dist/*.zip
release:
name: Create/Update Nightly Release
needs: [check-upstream, build-cli, build-opencode]
if: needs.check-upstream.outputs.should_build == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Download CLI Artifacts
uses: actions/download-artifact@v4
with:
pattern: cli-*
path: dist
merge-multiple: true
- name: Download OpenCode Artifacts
uses: actions/download-artifact@v4
with:
pattern: opencode-*
path: dist
merge-multiple: true
- name: List artifacts
run: |
echo "=== Downloaded artifacts ==="
find dist -type f | head -50
ls -la dist/ || true
- name: Package i18n tool
run: |
zip -r dist/opencode-i18n-tool-nightly.zip \
cli-go/ \
install.ps1 \
install.sh \
README.md \
CHANGELOG.md \
-x "cli-go/.git/*" \
-x "*.exe"
- name: Generate Release Notes
env:
NIGHTLY_DATE: ${{ needs.check-upstream.outputs.upstream_date }}
UPSTREAM_SHA: ${{ needs.check-upstream.outputs.upstream_sha }}
COMMIT_COUNT: ${{ needs.check-upstream.outputs.commit_count }}
CHANGELOG: ${{ needs.check-upstream.outputs.changelog }}
run: |
cat > release_notes.md << 'EOF'
## 🌙 Nightly Build - 自动跟进上游更新
> ⚠️ **警告**: 这是自动构建版本,可能包含未经充分测试的功能,不建议在生产环境使用。
> 如需稳定版本,请前往 [Releases](https://github.com/1186258278/OpenCodeChineseTranslation/releases) 页面下载正式版。
---
### 📊 构建信息
| 项目 | 值 |
|------|-----|
EOF
echo "| 上游分支 | \`${{ env.UPSTREAM_BRANCH }}\` |" >> release_notes.md
echo "| 上游 Commit | [\`${UPSTREAM_SHA:0:8}\`](https://github.com/${{ env.UPSTREAM_REPO }}/commit/$UPSTREAM_SHA) |" >> release_notes.md
echo "| 本次包含 Commits | ${COMMIT_COUNT:-unknown} |" >> release_notes.md
echo "| 构建时间 | $(TZ='Asia/Shanghai' date +"%Y-%m-%d %H:%M CST") |" >> release_notes.md
cat >> release_notes.md << 'EOF'
---
### 📦 下载
| 平台 | 管理工具 (CLI) | 汉化版 OpenCode |
|------|----------------|-----------------|
| Windows x64 | `opencode-cli-windows-amd64.exe` | `opencode-zh-CN-nightly-windows-x64.zip` |
| macOS Apple Silicon | `opencode-cli-darwin-arm64` | `opencode-zh-CN-nightly-darwin-arm64.zip` |
| macOS Intel | `opencode-cli-darwin-amd64` | `opencode-zh-CN-nightly-darwin-x64.zip` |
| Linux x64 | `opencode-cli-linux-amd64` | `opencode-zh-CN-nightly-linux-x64.zip` |
| Linux ARM64 | `opencode-cli-linux-arm64` | `opencode-zh-CN-nightly-linux-arm64.zip` |
> ⚠️ **注意**: Windows ARM64 暂不支持(Bun 尚未提供官方 Windows ARM64 构建)
---
### 📝 OpenCode 官方更新日志
以下是本次构建包含的上游更新:
EOF
if [ -n "$CHANGELOG" ]; then
echo "$CHANGELOG" >> release_notes.md
else
echo "_无法获取更新日志_" >> release_notes.md
fi
cat >> release_notes.md << 'EOF'
---
### 🔄 自动更新机制
- **检测频率**: 每小时检测一次上游更新
- **触发条件**: 累计 ≥5 个新 commit 时自动构建
- **更新方式**: 固定 `nightly` tag,每次构建覆盖更新
> 💡 此 Release 会持续更新,下载链接始终指向最新构建。
EOF
echo "=== Generated Release Notes ==="
cat release_notes.md
- name: Delete old nightly release
uses: dev-drprasad/delete-older-releases@v0.3.4
with:
keep_latest: 0
delete_tag_pattern: nightly
delete_tags: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
continue-on-error: true
- name: Create Nightly Release
uses: softprops/action-gh-release@v2
with:
tag_name: nightly
name: "🌙 Nightly Build (自动更新)"
body_path: release_notes.md
files: |
dist/*
draft: false
prerelease: true
make_latest: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update nightly state
env:
UPSTREAM_SHA: ${{ needs.check-upstream.outputs.upstream_sha }}
run: |
echo "$UPSTREAM_SHA" > .nightly-state
echo "Updated .nightly-state with SHA: $UPSTREAM_SHA"
# 提交状态文件
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .nightly-state
git commit -m "chore: update nightly build state [skip ci]
Upstream: ${{ env.UPSTREAM_REPO }}@${UPSTREAM_SHA:0:8}
Commits: ${{ needs.check-upstream.outputs.commit_count }}" || echo "No changes to commit"
git push || echo "Push failed, state will be updated on next run"
notify-skip:
name: Report Skip Reason
runs-on: ubuntu-latest
needs: check-upstream
if: needs.check-upstream.outputs.should_build != 'true'
steps:
- name: Report status
env:
COMMIT_COUNT: ${{ needs.check-upstream.outputs.commit_count }}
run: |
echo "=== Nightly Build Skipped ==="
echo "Reason: Not enough new commits"
echo "Current new commits: ${COMMIT_COUNT:-0}"
echo "Threshold: ${{ env.MIN_COMMITS_THRESHOLD }}"
echo ""
echo "Build will trigger when upstream has ≥${{ env.MIN_COMMITS_THRESHOLD }} new commits."
echo "You can also manually trigger with 'force_build=true' to skip this check."