78ebe063f3
新增 Jenkins 用户级 npm 10.9.7 版本隔离引导 在 Web Build 各独立 shell 复用固定 npm 后执行 workspace 安装与门禁 收紧生产运维检查并同步 npm workspaces 文档与共享决策
193 lines
8.3 KiB
Plaintext
193 lines
8.3 KiB
Plaintext
pipeline {
|
|
agent {
|
|
label 'linux && genarrative-build'
|
|
}
|
|
|
|
options {
|
|
disableConcurrentBuilds()
|
|
skipDefaultCheckout(true)
|
|
buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '20'))
|
|
copyArtifactPermission('Genarrative-Web-Deploy')
|
|
}
|
|
|
|
environment {
|
|
GIT_REMOTE_URL = 'ssh://git@127.0.0.1:2222/GenarrativeAI/Genarrative.git'
|
|
GIT_REMOTE_CREDENTIAL_ID = 'genarrative-local-gitea-ssh'
|
|
GIT_REMOTE_FALLBACK_URL = ''
|
|
GIT_REMOTE_FALLBACK_CREDENTIAL_ID = ''
|
|
GENARRATIVE_NPM_VERSION = '10.9.7'
|
|
}
|
|
|
|
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: 'RUN_NPM_CI', defaultValue: true, description: '构建前是否按根 workspace lockfile 执行一次 npm ci')
|
|
booleanParam(name: 'PUBLISH_AFTER_BUILD', defaultValue: false, description: '构建成功后是否触发 Web 发布')
|
|
string(name: 'DEPLOY_JOB_NAME', defaultValue: 'Genarrative-Web-Deploy', description: 'Web 发布流水线作业名')
|
|
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')
|
|
}
|
|
|
|
stages {
|
|
stage('Checkout') {
|
|
steps {
|
|
script {
|
|
def checkoutFromRemote = { String remoteUrl, String credentialsId ->
|
|
def remoteConfig = [url: remoteUrl, refspec: "+refs/heads/${params.SOURCE_BRANCH}:refs/remotes/origin/${params.SOURCE_BRANCH}"]
|
|
def checkoutCredentialId = credentialsId?.trim()
|
|
if (checkoutCredentialId) {
|
|
remoteConfig.credentialsId = checkoutCredentialId
|
|
}
|
|
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],
|
|
])
|
|
}
|
|
try {
|
|
checkoutFromRemote(env.GIT_REMOTE_URL, env.GIT_REMOTE_CREDENTIAL_ID)
|
|
env.EFFECTIVE_GIT_REMOTE_URL = env.GIT_REMOTE_URL
|
|
} catch (error) {
|
|
def fallbackRemoteUrl = env.GIT_REMOTE_FALLBACK_URL?.trim()
|
|
if (!fallbackRemoteUrl) {
|
|
throw error
|
|
}
|
|
echo "Git 主地址拉取失败: ${env.GIT_REMOTE_URL},改用备用地址: ${fallbackRemoteUrl}"
|
|
checkoutFromRemote(fallbackRemoteUrl, env.GIT_REMOTE_FALLBACK_CREDENTIAL_ID)
|
|
env.EFFECTIVE_GIT_REMOTE_URL = fallbackRemoteUrl
|
|
}
|
|
}
|
|
withCredentials([sshUserPrivateKey(credentialsId: env.GIT_REMOTE_CREDENTIAL_ID, keyFileVariable: 'GENARRATIVE_GIT_SSH_KEY')]) {
|
|
sh '''
|
|
bash -lc '
|
|
set -euo pipefail
|
|
chmod +x scripts/jenkins-checkout-source.sh
|
|
SOURCE_BRANCH="${SOURCE_BRANCH:-master}" \
|
|
COMMIT_HASH="${COMMIT_HASH:-}" \
|
|
GIT_REMOTE_URL="${EFFECTIVE_GIT_REMOTE_URL:-${GIT_REMOTE_URL}}" \
|
|
GIT_REMOTE_FALLBACK_URL="" \
|
|
SOURCE_COMMIT_FILE=".jenkins-source-commit" \
|
|
GENARRATIVE_JENKINS_REUSE_EXISTING_CHECKOUT="true" \
|
|
GIT_SSH_COMMAND="ssh -i ${GENARRATIVE_GIT_SSH_KEY:?GENARRATIVE_GIT_SSH_KEY 不能为空} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new" \
|
|
scripts/jenkins-checkout-source.sh
|
|
'
|
|
'''
|
|
}
|
|
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 Web') {
|
|
steps {
|
|
sh '''
|
|
bash -lc '
|
|
set -euo pipefail
|
|
source scripts/jenkins-prepare-npm-env.sh
|
|
actual_npm_version="$(npm --version)"
|
|
if [[ "${actual_npm_version}" != "${GENARRATIVE_NPM_VERSION}" ]]; then
|
|
echo "npm 版本不匹配:期望 ${GENARRATIVE_NPM_VERSION},实际 ${actual_npm_version}" >&2
|
|
exit 1
|
|
fi
|
|
'
|
|
'''
|
|
script {
|
|
if (params.RUN_NPM_CI) {
|
|
sh '''
|
|
bash -lc '
|
|
set -euo pipefail
|
|
source scripts/jenkins-prepare-npm-env.sh
|
|
npm ci
|
|
'
|
|
'''
|
|
}
|
|
}
|
|
sh '''
|
|
bash -lc '
|
|
set -euo pipefail
|
|
source scripts/jenkins-prepare-npm-env.sh
|
|
npm run check:encoding
|
|
npm run check:production-ops
|
|
npm run lint:eslint
|
|
npm run typecheck
|
|
npm run admin-web:typecheck
|
|
npm run test
|
|
SOURCE_BRANCH="${SOURCE_BRANCH}" SOURCE_COMMIT="${SOURCE_COMMIT}" \
|
|
npm run build:production-release -- --component web --name "${EFFECTIVE_BUILD_VERSION}"
|
|
'
|
|
'''
|
|
}
|
|
}
|
|
|
|
stage('Archive') {
|
|
steps {
|
|
archiveArtifacts artifacts: "build/${env.EFFECTIVE_BUILD_VERSION}/web.tar.gz,build/${env.EFFECTIVE_BUILD_VERSION}/web.tar.gz.sha256,build/${env.EFFECTIVE_BUILD_VERSION}/release-manifest.json,scripts/deploy/production-web-deploy.sh", 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),
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
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: 'Web 构建流水线结束'),
|
|
]
|
|
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 "Web 构建完成: version=${env.EFFECTIVE_BUILD_VERSION}, commit=${env.SOURCE_COMMIT}"
|
|
}
|
|
}
|
|
}
|