first commit

This commit is contained in:
qwer-xyz
2026-06-20 14:22:31 +08:00
commit c2498911ab
793 changed files with 291660 additions and 0 deletions
+190
View File
@@ -0,0 +1,190 @@
name: Agent Build & Release
on:
push:
branches:
- main
- dev
paths:
- 'agent/**'
- 'server/templates/agent-install.sh'
- 'server/src/routes/agent.ts'
- 'server/src/lib/agent-auth.ts'
- 'server/src/lib/host-agent-credentials.ts'
- 'server/src/services/agent-instance-report.ts'
- '.github/workflows/agent-release.yml'
pull_request:
branches:
- main
paths:
- 'agent/**'
- 'server/templates/agent-install.sh'
- 'server/src/routes/agent.ts'
- 'server/src/lib/agent-auth.ts'
- 'server/src/lib/host-agent-credentials.ts'
- 'server/src/services/agent-instance-report.ts'
- '.github/workflows/agent-release.yml'
workflow_dispatch:
inputs:
publish_release:
description: 'Publish an Agent GitHub Release using the version in agent/VERSION.'
required: false
default: false
type: boolean
env:
GO_VERSION: '1.22.x'
jobs:
version:
name: Resolve Agent Version
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version: ${{ steps.version.outputs.version }}
version_changed: ${{ steps.changed.outputs.version_changed }}
should_release: ${{ steps.release.outputs.should_release }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Read Agent version
id: version
shell: bash
run: |
set -euo pipefail
VERSION="$(tr -d '[:space:]' < agent/VERSION)"
if [[ ! "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "Invalid Agent version: ${VERSION}" >&2
echo "Expected vMAJOR.MINOR.PATCH or vMAJOR.MINOR.PATCH-suffix" >&2
exit 1
fi
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
echo "Agent version: ${VERSION}"
- name: Detect agent/VERSION change
id: changed
shell: bash
run: |
set -euo pipefail
VERSION_CHANGED=false
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
BEFORE="${{ github.event.before }}"
AFTER="${{ github.sha }}"
if [[ -z "${BEFORE}" || "${BEFORE}" =~ ^0+$ ]]; then
VERSION_CHANGED=true
elif git diff --name-only "${BEFORE}" "${AFTER}" | grep -qx 'agent/VERSION'; then
VERSION_CHANGED=true
fi
fi
echo "version_changed=${VERSION_CHANGED}" >> "${GITHUB_OUTPUT}"
echo "agent/VERSION changed: ${VERSION_CHANGED}"
- name: Decide release publishing
id: release
shell: bash
run: |
set -euo pipefail
SHOULD_RELEASE=false
if [[ "${GITHUB_EVENT_NAME}" == "push" && "${{ steps.changed.outputs.version_changed }}" == "true" ]]; then
SHOULD_RELEASE=true
elif [[ "${GITHUB_EVENT_NAME}" == "workflow_dispatch" && "${{ inputs.publish_release }}" == "true" ]]; then
SHOULD_RELEASE=true
fi
echo "should_release=${SHOULD_RELEASE}" >> "${GITHUB_OUTPUT}"
echo "should release: ${SHOULD_RELEASE}"
build-agent:
name: Build Agent
runs-on: ubuntu-latest
needs:
- version
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: agent/go.mod
- name: Test Agent
working-directory: agent
run: go test ./...
- name: Build Agent release files
run: VERSION="${{ needs.version.outputs.version }}" bash agent/scripts/build-release.sh
- name: Prepare release assets
shell: bash
run: |
set -euo pipefail
VERSION="${{ needs.version.outputs.version }}"
mkdir -p agent/release
cp agent/dist/incudal-agent-linux-amd64 "agent/release/incudal-agent-x86_64-${VERSION}"
cp agent/dist/incudal-agent-linux-arm64 "agent/release/incudal-agent-aarch64-${VERSION}"
- name: Verify release assets
shell: bash
run: |
set -euo pipefail
VERSION="${{ needs.version.outputs.version }}"
test -s "agent/release/incudal-agent-x86_64-${VERSION}"
test -s "agent/release/incudal-agent-aarch64-${VERSION}"
- name: Upload Agent artifacts
uses: actions/upload-artifact@v4
with:
name: incudal-agent-${{ needs.version.outputs.version }}
path: |
agent/release/incudal-agent-x86_64-${{ needs.version.outputs.version }}
agent/release/incudal-agent-aarch64-${{ needs.version.outputs.version }}
retention-days: 30
release-agent:
name: Publish Agent Release
runs-on: ubuntu-latest
needs:
- version
- build-agent
if: needs.version.outputs.should_release == 'true'
permissions:
contents: write
steps:
- name: Download Agent artifacts
uses: actions/download-artifact@v4
with:
name: incudal-agent-${{ needs.version.outputs.version }}
path: agent-release
- name: Publish GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: agent-${{ needs.version.outputs.version }}
target_commitish: ${{ github.sha }}
name: Incudal Agent ${{ needs.version.outputs.version }}
files: |
agent-release/incudal-agent-x86_64-${{ needs.version.outputs.version }}
agent-release/incudal-agent-aarch64-${{ needs.version.outputs.version }}
generate_release_notes: true
draft: false
prerelease: ${{ contains(needs.version.outputs.version, '-') }}
fail_on_unmatched_files: true
overwrite_files: true
+81
View File
@@ -0,0 +1,81 @@
name: CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main]
jobs:
lint-and-typecheck:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm --filter server exec prisma generate
env:
DATABASE_URL: postgresql://user:pass@localhost:5432/db
- name: Lint
run: pnpm lint
- name: Type check (client)
run: pnpm --filter client type-check
- name: Type check (server)
run: pnpm --filter server type-check
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'
cache-dependency-path: agent/go.mod
- name: Test Agent
working-directory: agent
run: go test ./...
build:
name: Build
runs-on: ubuntu-latest
needs: lint-and-typecheck
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile --ignore-scripts
- name: Generate Prisma Client
run: pnpm --filter server exec prisma generate
env:
DATABASE_URL: postgresql://user:pass@localhost:5432/db
- name: Build
run: pnpm build
+65
View File
@@ -0,0 +1,65 @@
name: Docker Build & Push
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Image tag (e.g., latest, v1.0.0)'
required: false
default: 'latest'
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
name: Build & Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
# For tags: v1.0.0 -> 1.0.0, latest
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
# For manual trigger
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }}
# Always tag latest for version tags
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
+257
View File
@@ -0,0 +1,257 @@
# ============================================================================
# Incudal 预构建产物包发布工作流
# 在推送版本 tag (v*) 或手动触发时,自动构建前后端并打包为 .tar.gz 发行包
# 支持 amd64 和 arm64 双架构
# ============================================================================
name: Build & Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: '发行版本号(例如 v1.0.0),留空则使用 git SHA 作为预览版'
required: false
default: ''
env:
NODE_VERSION: '22'
jobs:
# ===== 构建发行包(多架构矩阵) =====
build:
name: 构建 (${{ matrix.arch }})
runs-on: ${{ matrix.runner }}
strategy:
matrix:
include:
- arch: amd64
runner: ubuntu-latest
- arch: arm64
runner: ubuntu-24.04-arm
permissions:
contents: write
steps:
- name: 检出代码
uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
- name: 安装 Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
# ===== 安装依赖 =====
- name: 安装全部依赖
run: pnpm install --frozen-lockfile --ignore-scripts
- name: 重新构建 esbuildVite 构建需要)
run: pnpm rebuild esbuild
# ===== 生成 Prisma Client =====
- name: 生成 Prisma Client
run: pnpm --filter server exec prisma generate
env:
DATABASE_URL: postgresql://user:pass@localhost:5432/db
# ===== 构建前端 =====
- name: 构建前端 (Vite)
run: pnpm --filter client build
# ===== 构建后端 =====
- name: 编译后端 (TypeScript)
run: pnpm --filter server build
# ===== 准备发行目录 =====
- name: 准备发行目录结构
run: |
mkdir -p release/client/dist
mkdir -p release/server
# 复制前端构建产物
cp -r client/dist/* release/client/dist/
# 复制后端构建产物
cp -r server/dist release/server/
cp -r server/prisma release/server/
cp server/prisma.config.ts release/server/
cp server/package.json release/server/
cp -r server/templates release/server/
# 复制根配置文件
cp package.json release/
cp pnpm-workspace.yaml release/
# ===== 安装生产依赖 =====
- name: 安装后端生产依赖
working-directory: release/server
run: |
# 在发行目录中只安装生产依赖
npm install --omit=dev --ignore-scripts
# 在当前架构的 runner 上原生生成 Prisma Client
DATABASE_URL="postgresql://user:pass@localhost:5432/db" npx prisma generate
# ===== 创建启动辅助脚本 =====
- name: 创建管理脚本
run: |
cat > release/incudal.sh << 'SCRIPT'
#!/bin/bash
# Incudal 快捷管理脚本
set -e
APP_DIR="$(cd "$(dirname "$0")" && pwd)"
case "${1:-}" in
start)
echo "🚀 启动 Incudal..."
cd "$APP_DIR/server"
npx prisma migrate deploy
cd "$APP_DIR"
exec node server/dist/app.js
;;
migrate)
echo "🔄 执行数据库迁移..."
cd "$APP_DIR/server"
npx prisma migrate deploy
echo "✅ 迁移完成"
;;
version)
echo "Incudal $(node -e "console.log(require('./package.json').version)")"
;;
*)
echo "用法: $0 {start|migrate|version}"
exit 1
;;
esac
SCRIPT
chmod +x release/incudal.sh
# ===== 确定版本号 =====
- name: 确定版本号
id: version
run: |
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref_type }}" == "tag" ]]; then
VERSION="${{ github.ref_name }}"
elif [[ -n "${{ github.event.inputs.tag }}" ]]; then
VERSION="${{ github.event.inputs.tag }}"
else
VERSION="preview-$(echo ${{ github.sha }} | head -c 7)"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "📦 版本号: $VERSION"
# ===== 打包 =====
- name: 打包为 tar.gz
run: |
VERSION="${{ steps.version.outputs.version }}"
cd release
tar -czf "../incudal-${VERSION}-linux-${{ matrix.arch }}.tar.gz" .
cd ..
ls -lh "incudal-${VERSION}-linux-${{ matrix.arch }}.tar.gz"
echo "📦 发行包大小: $(du -h "incudal-${VERSION}-linux-${{ matrix.arch }}.tar.gz" | cut -f1)"
# ===== 上传构建产物 =====
- name: 上传构建产物
uses: actions/upload-artifact@v4
with:
name: incudal-${{ steps.version.outputs.version }}-linux-${{ matrix.arch }}
path: incudal-${{ steps.version.outputs.version }}-linux-${{ matrix.arch }}.tar.gz
retention-days: 30
# ===== 发布 Release(等待所有架构构建完成) =====
release:
name: 发布 Release
needs:
- build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: 确定版本号
id: version
run: echo "version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
# 下载所有架构的构建产物
- name: 下载 amd64 产物
uses: actions/download-artifact@v4
with:
name: incudal-${{ steps.version.outputs.version }}-linux-amd64
- name: 下载 arm64 产物
uses: actions/download-artifact@v4
with:
name: incudal-${{ steps.version.outputs.version }}-linux-arm64
- name: 列出发行文件
run: ls -lh incudal-*.tar.gz
# 创建 Release 并上传所有架构的产物
- name: 创建 GitHub Release
uses: softprops/action-gh-release@v2
with:
files: |
incudal-*.tar.gz
generate_release_notes: true
draft: false
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc') }}
# ===== 构建并推送 Docker 镜像(多架构) =====
docker:
name: 构建 Docker 镜像
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: 检出代码
uses: actions/checkout@v4
# 设置 QEMU(用于跨架构构建 arm64)
- name: 设置 QEMU
uses: docker/setup-qemu-action@v3
# 设置 Docker Buildx(多架构构建引擎)
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v3
# 登录 GitHub Container Registry
- name: 登录 GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 提取版本号和元数据
- name: 提取 Docker 元数据
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
# 构建并推送多架构镜像
- name: 构建并推送 Docker 镜像
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max