Repository navigation
feat(book-variants): name the localization tab by which plugin is on #176
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: Deploy to Production | |
| # push 到 dev 分支(或手动触发):构建 → 上传 → 原子切换 → 健康检查 | |
| on: | |
| push: | |
| branches: [dev] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| env: | |
| NODE_VERSION: "24.20.0" | |
| concurrency: | |
| group: infosphere-production | |
| cancel-in-progress: false | |
| jobs: | |
| build-and-deploy: | |
| runs-on: ubuntu-latest | |
| environment: production | |
| steps: | |
| - name: Checkout source | |
| uses: actions/checkout@v6 | |
| # ── 前端:类型检查 + lint + SSR 构建 ── | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: pnpm | |
| cache-dependency-path: app/web/pnpm-lock.yaml | |
| - name: Install web dependencies | |
| working-directory: app/web | |
| run: pnpm install --frozen-lockfile | |
| - name: Typecheck, test and lint web | |
| working-directory: app/web | |
| run: | | |
| pnpm exec tsc --noEmit | |
| pnpm test | |
| pnpm exec next lint | |
| - name: Build web (SSR standalone) | |
| working-directory: app/web | |
| env: | |
| NEXT_DIST_DIR: .next-build | |
| run: pnpm build | |
| - name: Package embedded web runtime | |
| run: deploy/package-web-runtime.sh "$NODE_VERSION" linux amd64 server/internal/webbundle/assets/web-runtime.tar.gz | |
| # ── 单文件:Go API + Next.js standalone + Node.js 24 ── | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version-file: server/go.mod | |
| cache-dependency-path: server/go.sum | |
| - name: Vet and test backend | |
| working-directory: server | |
| run: | | |
| go vet ./... | |
| go test ./... | |
| - name: Build Linux backend | |
| working-directory: server | |
| env: | |
| CGO_ENABLED: "0" | |
| GOOS: linux | |
| GOARCH: amd64 | |
| COMMIT_SHA: ${{ github.sha }} | |
| run: | | |
| mkdir -p ../release | |
| go build -trimpath \ | |
| -ldflags="-s -w \ | |
| -X 'infosphere/server/internal/app.Commit=${COMMIT_SHA::7}' \ | |
| -X 'infosphere/server/internal/app.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)'" \ | |
| -o ../release/infosphere-server . | |
| # ── 打包发布:只有一个应用二进制 + systemd unit + env ── | |
| - name: Assemble release | |
| env: | |
| INFO_SPHERE_ENV_FILE: ${{ secrets.INFO_SPHERE_ENV_FILE }} | |
| run: | | |
| test -n "$INFO_SPHERE_ENV_FILE" | |
| cp deploy/infosphere-api.service deploy/infosphere.sudoers release/ | |
| printf '%s\n' "$INFO_SPHERE_ENV_FILE" > release/infosphere.env | |
| chmod 600 release/infosphere.env | |
| (cd release && sha256sum infosphere-server > SHA256SUMS) | |
| ls -la release/ | |
| - name: Upload release to server | |
| uses: appleboy/scp-action@v1.0.0 | |
| with: | |
| host: ${{ secrets.SSH_PRIVATE_HOST }} | |
| username: ${{ secrets.SSH_PRIVATE_USER }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| source: "release/*" | |
| target: "/tmp/infosphere-release-${{ github.sha }}" | |
| strip_components: 1 | |
| - name: Activate release | |
| uses: appleboy/ssh-action@v1.2.5 | |
| env: | |
| RELEASE_SHA: ${{ github.sha }} | |
| with: | |
| host: ${{ secrets.SSH_PRIVATE_HOST }} | |
| username: ${{ secrets.SSH_PRIVATE_USER }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| envs: RELEASE_SHA | |
| script: | | |
| set -eu | |
| deploy_root=/var/www/infosphere | |
| staged_dir=/tmp/infosphere-release-$RELEASE_SHA | |
| release_dir=$deploy_root/releases/$RELEASE_SHA | |
| test -f "$staged_dir/infosphere-server" | |
| test -s "$staged_dir/infosphere.env" | |
| # 目录骨架 | |
| sudo install -d -m 755 "$deploy_root/releases" "$release_dir" /etc/infosphere | |
| sudo install -d -m 755 -o www-data -g www-data /var/lib/infosphere /var/lib/infosphere/uploads | |
| sudo install -d -m 755 -o www-data -g www-data /var/www/infosphere/static | |
| # 发布单文件 | |
| sudo cp -a "$staged_dir/." "$release_dir/" | |
| sudo chmod 755 "$release_dir/infosphere-server" | |
| # 配置与服务 | |
| sudo install -m 600 "$release_dir/infosphere.env" /etc/infosphere/infosphere.env | |
| sudo install -m 644 "$release_dir/infosphere-api.service" /etc/systemd/system/infosphere-api.service | |
| sudo install -m 440 "$release_dir/infosphere.sudoers" /etc/sudoers.d/infosphere | |
| sudo visudo -c >/dev/null | |
| # 原子切换 current | |
| sudo ln -sfn "$release_dir" "$deploy_root/current.next" | |
| sudo mv -Tf "$deploy_root/current.next" "$deploy_root/current" | |
| # 首次单文件部署时停止并禁用旧的独立 Web unit,释放 6900 给 Go 托管的 Node 子进程 | |
| sudo systemctl disable --now infosphere-web.service || true | |
| sudo systemctl daemon-reload | |
| sudo systemctl enable infosphere-api.service | |
| sudo systemctl restart infosphere-api.service | |
| # 健康检查:单服务包含当前 commit,内嵌 Web 与 Go 页面代理均可访问 | |
| attempt=0 | |
| until curl -fsS http://127.0.0.1:6969/api/v1/health | grep -q "\"commit\":\"${RELEASE_SHA::7}\"" \ | |
| && curl -fsS -o /dev/null http://127.0.0.1:6900/ \ | |
| && curl -fsS -o /dev/null http://127.0.0.1:6969/; do | |
| attempt=$((attempt + 1)) | |
| if [ "$attempt" -ge 15 ]; then | |
| sudo systemctl status infosphere-api.service --no-pager || true | |
| sudo journalctl -u infosphere-api.service -n 30 --no-pager || true | |
| exit 1 | |
| fi | |
| sleep 2 | |
| done | |
| # 清理:仅保留最近 5 个版本 | |
| sudo bash -c "ls -1dt $deploy_root/releases/*/ | tail -n +6 | xargs -r rm -rf" | |
| rm -rf "$staged_dir" | |
| echo "InfoSphere 部署完成: $release_dir" |