pipeline { agent { label 'built-in && windows' } options { disableConcurrentBuilds() skipDefaultCheckout(true) buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '20')) } environment { GIT_REMOTE_URL = 'http://82.157.175.59:3000/GenarrativeAI/Genarrative.git' CARGO_HOME = '${env.WORKSPACE_TMP}/cargo-home' CARGO_TARGET_DIR = '${env.WORKSPACE_TMP}/cargo-target/prod-release' CARGO_INCREMENTAL = '0' RUSTC_WRAPPER = 'sccache' SCCACHE_DIR = '${env.USERPROFILE}\\.cache\\sccache-stdb-module' SCCACHE_CACHE_SIZE = '30G' } parameters { string(name: 'SOURCE_BRANCH', defaultValue: 'master', description: '源码分支,默认 master 最新提交') string(name: 'COMMIT_HASH', defaultValue: '', description: '可选,指定属于 SOURCE_BRANCH 的 Git commit') string(name: 'BUILD_VERSION', defaultValue: '', description: '发布版本号,留空则使用 Jenkins BUILD_NUMBER') string(name: 'NOTIFICATION_EMAILS', defaultValue: '', description: '本次运行追加通知邮箱;会与 Jenkins Secret Text 凭据 genarrative-notification-emails 合并发送') booleanParam(name: 'PUBLISH_AFTER_BUILD', defaultValue: false, description: '构建成功后是否触发 Stdb module 发布') string(name: 'DEPLOY_JOB_NAME', defaultValue: 'Genarrative-Stdb-Module-Publish', description: 'Stdb module 发布流水线作业名') choice(name: 'DEPLOY_TARGET', choices: ['development', 'release'], description: 'PUBLISH_AFTER_BUILD=true 时的逻辑部署目标;development 使用当前 Linux 开发/构建/开发部署 agent') booleanParam(name: 'CONFIRM_RELEASE_DEPLOY_AGENT', defaultValue: false, description: 'PUBLISH_AFTER_BUILD=true 且目标为 release 时必须确认已有独立 release 部署 agent') string(name: 'DATABASE', defaultValue: 'genarrative-prod', description: '生产 SpacetimeDB database') } stages { stage('Checkout') { steps { checkout([ $class: 'GitSCM', branches: [[name: "*/${params.SOURCE_BRANCH}"]], doGenerateSubmoduleConfigurations: false, extensions: [ [$class: 'CleanBeforeCheckout'], [$class: 'CloneOption', shallow: true, depth: 1, noTags: true, timeout: 30], ], userRemoteConfigs: [[url: "${GIT_REMOTE_URL}"]], ]) powershell ''' $ErrorActionPreference = 'Stop' $sourceBranch = if ($env:SOURCE_BRANCH) { $env:SOURCE_BRANCH } else { 'master' } $commitHash = if ($env:COMMIT_HASH) { $env:COMMIT_HASH } else { '' } $gitRemoteUrl = if ($env:GIT_REMOTE_URL) { $env:GIT_REMOTE_URL } else { 'http://82.157.175.59:3000/GenarrativeAI/Genarrative.git' } git fetch --no-tags --prune --depth=1 $gitRemoteUrl "+refs/heads/${sourceBranch}:refs/remotes/origin/${sourceBranch}" if ($commitHash) { git checkout --force $commitHash } else { git checkout --force "origin/$sourceBranch" } git clean -ffdx git rev-parse HEAD | Set-Content -Encoding UTF8 .jenkins-source-commit ''' script { env.SOURCE_COMMIT = readFile('.jenkins-source-commit').trim() env.EFFECTIVE_BUILD_VERSION = params.BUILD_VERSION?.trim() ? params.BUILD_VERSION.trim() : env.BUILD_NUMBER } } } stage('Build Stdb Module') { steps { powershell ''' $ErrorActionPreference = 'Stop' $workspaceTmp = if ($env:WORKSPACE_TMP) { $env:WORKSPACE_TMP } else { "$env:WORKSPACE@tmp" } $effectiveBuildVersion = if ($env:EFFECTIVE_BUILD_VERSION) { $env:EFFECTIVE_BUILD_VERSION } elseif ($env:BUILD_VERSION) { $env:BUILD_VERSION } else { $env:BUILD_NUMBER } $env:CARGO_HOME = "$workspaceTmp/cargo-home" $env:CARGO_TARGET_DIR = "$workspaceTmp/cargo-target/prod-release" $env:SCCACHE_DIR = "$env:USERPROFILE/.cache/sccache-stdb-module" $env:PATH = "$env:CARGO_HOME/bin;$env:PATH" if (-not (Get-Command bash -ErrorAction SilentlyContinue)) { throw '[stdb-build] Windows 构建节点缺少 bash,无法执行仓库现有生产构建脚本。请先安装 Git Bash 或 WSL bash,并确保 bash 在 PATH 中。' } $bashScript = @" set -euo pipefail export CARGO_HOME="`$(cygpath -u '$($env:CARGO_HOME)')" export CARGO_TARGET_DIR="`$(cygpath -u '$($env:CARGO_TARGET_DIR)')" export SCCACHE_DIR="`$(cygpath -u '$($env:SCCACHE_DIR)')" export CARGO_INCREMENTAL='$($env:CARGO_INCREMENTAL)' export RUSTC_WRAPPER='$($env:RUSTC_WRAPPER)' export SCCACHE_CACHE_SIZE='$($env:SCCACHE_CACHE_SIZE)' export SOURCE_BRANCH='$($env:SOURCE_BRANCH)' export SOURCE_COMMIT='$($env:SOURCE_COMMIT)' export EFFECTIVE_BUILD_VERSION='$effectiveBuildVersion' chmod +x scripts/jenkins-prepare-cargo-env.sh source scripts/jenkins-prepare-cargo-env.sh if ! command -v cargo >/dev/null 2>&1; then echo '[stdb-build] 缺少 cargo。请先在 Windows 构建节点安装 Rust 工具链。' >&2 exit 1 fi if ! command -v sccache >/dev/null 2>&1; then echo '[stdb-build] 未找到 sccache,改用 rustc 直接构建。' unset RUSTC_WRAPPER fi npm run build:production-release -- --component spacetime-module --name "`$EFFECTIVE_BUILD_VERSION" "@ bash -lc $bashScript ''' } } stage('Archive') { steps { archiveArtifacts artifacts: "build/${env.EFFECTIVE_BUILD_VERSION}/spacetime_module.wasm,build/${env.EFFECTIVE_BUILD_VERSION}/spacetime_module.wasm.sha256,build/${env.EFFECTIVE_BUILD_VERSION}/release-manifest.json", fingerprint: true } } stage('Publish') { when { expression { return params.PUBLISH_AFTER_BUILD } } steps { build job: params.DEPLOY_JOB_NAME, wait: true, propagate: true, parameters: [ string(name: 'SOURCE_BRANCH', value: params.SOURCE_BRANCH), string(name: 'COMMIT_HASH', value: env.SOURCE_COMMIT), string(name: 'BUILD_VERSION', value: env.EFFECTIVE_BUILD_VERSION), string(name: 'NOTIFICATION_EMAILS', value: params.NOTIFICATION_EMAILS ?: ''), string(name: 'DEPLOY_TARGET', value: params.DEPLOY_TARGET), booleanParam(name: 'CONFIRM_RELEASE_DEPLOY_AGENT', value: params.CONFIRM_RELEASE_DEPLOY_AGENT), string(name: 'BUILD_JOB_NAME', value: env.JOB_NAME), string(name: 'BUILD_NUMBER_TO_DEPLOY', value: env.BUILD_NUMBER), string(name: 'DATABASE', value: params.DATABASE), ] } } } post { always { script { def notificationParameters = [ string(name: 'SOURCE_JOB_NAME', value: env.JOB_NAME), string(name: 'SOURCE_BUILD_NUMBER', value: env.BUILD_NUMBER), string(name: 'SOURCE_BUILD_URL', value: env.BUILD_URL ?: ''), string(name: 'SOURCE_RESULT', value: currentBuild.currentResult ?: 'UNKNOWN'), string(name: 'SOURCE_BRANCH', value: params.SOURCE_BRANCH ?: ''), string(name: 'SOURCE_COMMIT', value: env.SOURCE_COMMIT ?: (params.COMMIT_HASH ?: '')), string(name: 'BUILD_VERSION', value: env.EFFECTIVE_BUILD_VERSION ?: (params.BUILD_VERSION ?: '')), string(name: 'DEPLOY_TARGET', value: params.DEPLOY_TARGET ?: ''), string(name: 'DATABASE', value: params.DATABASE ?: ''), string(name: 'SUMMARY', value: 'Stdb module 构建流水线结束'), ] def notificationRecipients = params.NOTIFICATION_EMAILS?.trim() if (notificationRecipients) { notificationParameters.add(string(name: 'EMAIL_RECIPIENTS', value: notificationRecipients)) } try { build job: 'Genarrative-Notify-Email', wait: false, propagate: false, parameters: notificationParameters } catch (error) { echo "邮件通知触发失败: ${error.message}" } } } success { echo "Stdb module 构建完成: version=${env.EFFECTIVE_BUILD_VERSION}, commit=${env.SOURCE_COMMIT}" } } }