Files
Genarrative/jenkins/Jenkinsfile.preview-deployer
kdletters 8ed0626627
Project CI / Frontend tests (push) Successful in 3m15s
Project CI / Repository checks (push) Successful in 2m12s
Project CI / Backend tests (push) Successful in 7m31s
Project CI / Native shell tests (push) Successful in 20m0s
恢复预览环境本地配置注入
恢复 API 与 worker 的 .env.local BuildKit secret 挂载

补齐 Jenkins 固定文件校验与预览文档

增加双配置文件构建门禁
2026-09-03 11:38:40 +08:00

155 lines
5.9 KiB
Plaintext

pipeline {
agent {
label 'linux && genarrative-build'
}
options {
disableConcurrentBuilds()
skipDefaultCheckout(true)
timeout(time: 120, unit: 'MINUTES')
buildDiscarder(logRotator(numToKeepStr: '50', artifactNumToKeepStr: '50'))
}
environment {
GIT_REMOTE_URL = 'ssh://git@127.0.0.1:2222/GenarrativeAI/Genarrative.git'
GIT_REMOTE_CREDENTIAL_ID = 'genarrative-local-gitea-ssh'
GENARRATIVE_PREVIEW_STATE_ROOT = '/data/jenkins/preview-deployments'
GENARRATIVE_PREVIEW_SECRETS_FILE = '/data/jenkins/preview-secrets/.env.secrets.local'
GENARRATIVE_PREVIEW_ENV_LOCAL_FILE = '/data/jenkins/preview-secrets/.env.local'
GENARRATIVE_PREVIEW_WEB_HOST = '192.168.35.82'
}
parameters {
choice(name: 'ACTION', choices: ['DEPLOY', 'STATUS', 'UNINSTALL'], description: '部署、查询状态或卸载分支预览容器')
string(name: 'SOURCE_BRANCH', defaultValue: '', description: '源码分支;DEPLOY 必填,同一分支稳定映射到同一个预览实例')
string(name: 'COMMIT_HASH', defaultValue: '', description: '可选;必须是 SOURCE_BRANCH 历史中的 commit')
string(name: 'DEPLOYMENT_ID', defaultValue: '', description: '可选;留空时由 SOURCE_BRANCH 稳定生成,查询和卸载可直接传部署 ID')
}
stages {
stage('Checkout Controller') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [
[$class: 'CleanBeforeCheckout'],
[$class: 'CloneOption', shallow: true, depth: 1, noTags: true, timeout: 30, honorRefspec: true],
],
userRemoteConfigs: [[
url: env.GIT_REMOTE_URL,
credentialsId: env.GIT_REMOTE_CREDENTIAL_ID,
refspec: '+refs/heads/master:refs/remotes/origin/master',
]],
])
}
}
stage('Validate Request') {
steps {
sh '''
set -euo pipefail
ACTION="${ACTION:-}"
SOURCE_BRANCH="${SOURCE_BRANCH:-}"
COMMIT_HASH="${COMMIT_HASH:-}"
DEPLOYMENT_ID="${DEPLOYMENT_ID:-}"
case "${ACTION}" in DEPLOY|STATUS|UNINSTALL) ;; *) exit 1 ;; esac
if [ -n "${SOURCE_BRANCH}" ]; then
git check-ref-format --branch "${SOURCE_BRANCH}" >/dev/null
fi
if [ -n "${COMMIT_HASH}" ] && ! printf '%s' "${COMMIT_HASH}" | grep -Eq '^[0-9a-fA-F]{7,40}$'; then
echo 'COMMIT_HASH 只能填写 7 到 40 位十六进制 Git commit hash。' >&2
exit 1
fi
if [ -n "${DEPLOYMENT_ID}" ] && ! printf '%s' "${DEPLOYMENT_ID}" | grep -Eq '^preview-[0-9a-f]{16}$'; then
echo 'DEPLOYMENT_ID 格式非法。' >&2
exit 1
fi
'''
}
}
stage('Checkout Requested Source') {
when {
expression { params.ACTION == 'DEPLOY' }
}
steps {
dir('source') {
script {
def remoteConfig = [
url: env.GIT_REMOTE_URL,
credentialsId: env.GIT_REMOTE_CREDENTIAL_ID,
refspec: "+refs/heads/${params.SOURCE_BRANCH}:refs/remotes/origin/${params.SOURCE_BRANCH}",
]
checkout([
$class: 'GitSCM',
branches: [[name: "*/${params.SOURCE_BRANCH}"]],
doGenerateSubmoduleConfigurations: false,
extensions: [
[$class: 'CleanBeforeCheckout'],
[$class: 'CloneOption', shallow: true, depth: 1, noTags: true, timeout: 30, honorRefspec: true],
],
userRemoteConfigs: [remoteConfig],
])
}
withCredentials([sshUserPrivateKey(credentialsId: env.GIT_REMOTE_CREDENTIAL_ID, keyFileVariable: 'GENARRATIVE_GIT_SSH_KEY')]) {
sh '''
set -euo pipefail
SOURCE_BRANCH="${SOURCE_BRANCH:-}" \
COMMIT_HASH="${COMMIT_HASH:-}" \
GIT_REMOTE_URL="${GIT_REMOTE_URL:-}" \
SOURCE_COMMIT_FILE=".jenkins-source-commit" \
GENARRATIVE_JENKINS_REUSE_EXISTING_CHECKOUT="true" \
GIT_SSH_COMMAND="ssh -i ${GENARRATIVE_GIT_SSH_KEY} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new" \
bash "${WORKSPACE}/scripts/jenkins-checkout-source.sh"
'''
}
}
}
}
stage('Execute Preview Action') {
steps {
sh '''
set -euo pipefail
chmod +x scripts/jenkins-preview-deployer.sh
SOURCE_DIR="${WORKSPACE}/source" \
RESULT_FILE="${WORKSPACE}/preview-result.json" \
DESCRIPTION_FILE="${WORKSPACE}/.jenkins-preview-description" \
scripts/jenkins-preview-deployer.sh
'''
script {
if (fileExists('.jenkins-preview-description')) {
currentBuild.description = readFile('.jenkins-preview-description').trim()
}
}
}
}
}
post {
always {
script {
if (!fileExists('preview-result.json')) {
writeFile file: 'preview-result.json', text: groovy.json.JsonOutput.prettyPrint(groovy.json.JsonOutput.toJson([
schemaVersion: 1,
action: params.ACTION ?: 'UNKNOWN',
deploymentId: params.DEPLOYMENT_ID ?: null,
projectName: params.DEPLOYMENT_ID ? "genarrative-${params.DEPLOYMENT_ID}" : null,
branch: params.SOURCE_BRANCH ?: null,
requestedCommit: params.COMMIT_HASH ?: null,
resolvedCommit: null,
status: 'failed',
health: 'unknown',
webUrl: null,
message: 'Jenkins 在生成部署结果前失败,请查看构建日志。',
updatedAt: new Date().format("yyyy-MM-dd'T'HH:mm:ssXXX"),
])) + '\n'
}
}
archiveArtifacts artifacts: 'preview-result.json', allowEmptyArchive: false, fingerprint: true
}
}
}