pipeline { agent any options { buildDiscarder(logRotator(numToKeepStr: '30', artifactNumToKeepStr: '30')) disableConcurrentBuilds() skipDefaultCheckout(true) timestamps() timeout(time: 60, unit: 'MINUTES') } parameters { string(name: 'NAPCAT_FORK_REF', defaultValue: 'codex/qr-refresh-login-state', description: 'Reviewed NapCatQQ fork branch, tag, or commit.') string(name: 'UPSTREAM_RELEASE_TAG', defaultValue: '', description: 'Reviewed upstream release tag, when applicable.') string(name: 'QQBOT_NAPCAT_IMAGE_OVERRIDE', defaultValue: '', description: 'Explicit runtime image tag to build or promote, for example kt-napcat-desktop-cn:desktop-cn-v9.') string(name: 'QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE', defaultValue: '', description: 'Explicit API desktop profile version override.') booleanParam(name: 'BUILD_RUNTIME_IMAGE', defaultValue: false, description: 'When true, trigger the reviewed Jenkins runtime image build/publish job.') choice(name: 'RUNTIME_BUILD_JOB', choices: ['KT-NapCatQQ/Runtime-Image-Build'], description: 'Whitelisted Jenkins job that performs the reviewed runtime image build and publish.') booleanParam(name: 'PROMOTE_API_RUNTIME', defaultValue: false, description: 'When true, trigger API promotion with explicit image/profile overrides.') choice(name: 'API_PROMOTION_JOB', choices: ['KT-Template/KT-Template-API/main'], description: 'Whitelisted API Jenkins job that accepts NapCat runtime override parameters.') string(name: 'CONFIRM_API_PROMOTION_TARGET', defaultValue: '', description: 'Type PROMOTE_KT_TEMPLATE_API_MAIN before triggering the production API promotion job.') } environment { KT_WORKSPACE_ROOT = '/vol1/docker/kt-codex/workspace/KT' KT_WORKFLOW_DIR = '/vol1/docker/kt-codex/workspace/KT/mcp/ktWorkflow' KT_ARTIFACT_ROOT = '/vol1/docker/kt-codex/artifacts' } stages { stage('ktWorkflow readiness') { steps { sh ''' set -e pnpm --dir "$KT_WORKFLOW_DIR" run napcat-runtime-release-readiness -- \ --artifact-root "$KT_ARTIFACT_ROOT/napcat-runtime-release" \ --fork-branch "$NAPCAT_FORK_REF" \ --upstream-release-tag "$UPSTREAM_RELEASE_TAG" \ --napcat-image-tag "$QQBOT_NAPCAT_IMAGE_OVERRIDE" \ --profile "$QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE" ''' } } stage('Runtime image build and publish') { when { expression { return params.BUILD_RUNTIME_IMAGE } } steps { script { requireRuntimeOverrides( params.QQBOT_NAPCAT_IMAGE_OVERRIDE, params.QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE ) build job: params.RUNTIME_BUILD_JOB, wait: true, parameters: [ string(name: 'NAPCAT_FORK_REF', value: params.NAPCAT_FORK_REF), string(name: 'UPSTREAM_RELEASE_TAG', value: params.UPSTREAM_RELEASE_TAG), string(name: 'QQBOT_NAPCAT_IMAGE_OVERRIDE', value: params.QQBOT_NAPCAT_IMAGE_OVERRIDE), string(name: 'QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE', value: params.QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE), string(name: 'KT_ARTIFACT_ROOT', value: "${env.KT_ARTIFACT_ROOT}/napcat-runtime-release") ] } } } stage('API promotion') { when { expression { return params.PROMOTE_API_RUNTIME } } steps { script { if (params.CONFIRM_API_PROMOTION_TARGET != 'PROMOTE_KT_TEMPLATE_API_MAIN') { error('CONFIRM_API_PROMOTION_TARGET must equal PROMOTE_KT_TEMPLATE_API_MAIN before API promotion runs.') } requireRuntimeOverrides( params.QQBOT_NAPCAT_IMAGE_OVERRIDE, params.QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE ) build job: params.API_PROMOTION_JOB, wait: true, parameters: [ string(name: 'QQBOT_NAPCAT_IMAGE_OVERRIDE', value: params.QQBOT_NAPCAT_IMAGE_OVERRIDE), string(name: 'QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE', value: params.QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE) ] } } } } post { always { sh ''' set +e rm -rf "$WORKSPACE/artifacts" mkdir -p "$WORKSPACE/artifacts/napcat-runtime-release" cp -a "$KT_ARTIFACT_ROOT/napcat-runtime-release/." "$WORKSPACE/artifacts/napcat-runtime-release/" 2>/dev/null || true ''' archiveArtifacts artifacts: 'artifacts/napcat-runtime-release/**/*', allowEmptyArchive: true, fingerprint: false } } } /** * Stops runtime build or promotion unless both release override values are explicit. * @param imageTag Reviewed NapCat runtime image tag supplied by the operator. * @param profile Reviewed desktop profile version supplied by the operator. * @return Nothing; aborts this pipeline through `error` when a required value is missing. */ void requireRuntimeOverrides(String imageTag, String profile) { if (!imageTag?.trim()) { error('QQBOT_NAPCAT_IMAGE_OVERRIDE is required before build or promotion.') } if (!profile?.trim()) { error('QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE is required before build or promotion.') } }