koca-admin-resource-making Admin门户资源制作流水线

1、资源整体介绍

资源分为以下块
a:Admin微服务标准门户资源,分VUE2和VUE3二个版本

 数据库脚本、后台jar、前端web编译后的dist包、nginx配置文件

b:Admin单体开发态门户资源,分VUE2和VUE3二个版本

数据库脚本、后台单体bootapp、前端源代码工程

c:Admin单体运行态门户资源,分VUE2和VUE3二个版本

数据库脚本、后台Jar(前端编译好的dist整合到了jar包中)

2、资源用途介绍

Admin微服务标准门户资源

此资源主要是方便客户快速搭建ADMIN V2和V3的演示环境
具体操作就是执行数据库、启动后台、前端放到nginx,启动nginx

Admin单体开发态门户资源

此资源主要是方便客户进行开发时使用
具体操作是执行数据库脚本,通过IDEA启动bootapp,启动前端工程,可基于之上做开发

Admin单体运行态门户资源

此资源主要是方便客户进行快速部署演示环境,单体模式部署更简单
具体操作是执行数据库脚本,再启动后台jar

3、整体执行流程

4、资源结构

Gitlab资源

admin-msa

admin-standalone

目标门户资源结构

jenjinsfile

import java.io.File

// 数据库对象
class FromDatabase {
    String type
    def jdbc
    def sqlPath
}

// web对象
class Web {
    def archetypeAndUi
    def args
    def modules
}

// 服务对象
class Server {
    String name
    String port
    def args
}

// 项目对象
class Project {
    // 项目名
    def name
    // 服务列表
    def servers
    // web模块
    def webs
    // 数据库模块
    def fromDatabases
}

// 读取yaml文件
def readYaml(String filePath) {
    def data = readYaml file: "$filePath"
    return data
}

def projectv2
def projectv3
// 初始化project
def initProject(String yamlPath){
    def project = new Project()
    def data = readYaml(yamlPath)
    // 获取项目名
    project.name = data.project.name
    // 获取服务列表
    def servers = new ArrayList()
    for(item in data.project.server) {
        def server = new Server()
        server.name = item.name
        server.port = item.port
        server.args = item.args
        servers.add(server)
    }
    project.servers = servers
    // 获取web模块
    def web = new Web()
    web.archetypeAndUi = data.project.web.archetypeAndUi
    web.args = data.project.web.args
    web.modules = data.project.web.modules
    project.webs = web
    // 获取数据库模块
    def fromDatabases = new ArrayList()
    for(item in data.project.fromDatabase) {
        def fromDatabase = new FromDatabase()
        fromDatabase.type = item.type
        fromDatabase.jdbc = item.jdbc
        fromDatabase.sqlPath = item.sqlPath
        fromDatabases.add(fromDatabase)
    }
    project.fromDatabases = fromDatabases
    
    return project
}

/**
 * git克隆
 * remoteAddr:仓库地址 如:http://ip:port/KOCA/koca-devops.git
 * branch:git分支 如:refs/heads/develop
 * credentialsId:git用户凭证
 * dirName:git克隆在dirName目录下
 */ 
def gitClone(String remoteAddr, String branch, String credentialsId,String dirName) {
    dir(dirName){
        checkout([$class: 'GitSCM',
            branches: [[name: (branch)]], doGenerateSubmoduleConfigurations: false, 
            extensions: [], submoduleCfg: [], 
            userRemoteConfigs: [[credentialsId: (credentialsId), url: (remoteAddr)]]])
    }
}


/**
 * 拷贝bootapp
 * vueVersion: vue的版本(v2,v3)
 * srcPath:从git拉取下来的bootapp的路径
 * targetPath:交付资源的目录
 * 注:bootapp的命名方式:koca-admin-standalone-vue版本-bootapp
 */ 
def copyBootapp(String vueVersion,String srcPath,String targetPath){
    sh """
        cp -r ${srcPath}/koca-admin-standalone-${vueVersion}-bootapp ${targetPath}
    """
}

/**
 * 拷贝README.md说明文档
 * srcPath:源README.md的路径
 * targetPath:交付资源的目录
 */ 
def copyReadMe(String srcPath,String targetPath){
    sh """
        cp ${srcPath}/README.md ${targetPath}
    """
}

/**
 * 拷贝pkg目录
 * srcPath:源pgk的路径
 * targetPath:交付资源的目录
 */ 
def copyPkg(String srcPath,String targetPath) {
    sh """
        cp -r ${srcPath}/pkg ${targetPath}
    """
}

def compileWeb(String vueVersion,String targetWebPath) {

    if(vueVersion == "v2") {
        sh """
            cd ${targetPath}
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"  # This loads nvm
            [ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion"
            sh /root/.nvm/nvm.sh
            nvm use 14
            node -v
            kc -v

            pnpm install
            pnpm build

            cd -
        """
    }

    else {
          sh """
            cd ${targetPath}
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"  # This loads nvm
            [ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion"
            sh /root/.nvm/nvm.sh
            nvm use 16
            node -v
            kc -v

            pnpm install
            pnpm build

            cd -
        """ 
    }
}

def compileServer(String targetPath) {
    sh """
        cd ${targetPath}/koca-admin-standalone-*-bootapp
        mvn clean package
        cd -
    """
}

def copyServerJarToPkg(String targetPath) {
    sh """
        cd ${targetPath}/koca-admin-standalone-*-bootapp/target
        cp koca-admin-standalone-*.jar ${targetPath}/pgk/lib
        cd -
    """
}

def putWebDistToBooApp(String targetPath) {
    sh """
        rm -rf ${targetPath}/koca-admin-standalone-*-bootapp/src/main/resources/static
        mkdir -p ${targetPath}/koca-admin-standalone-*-bootapp/src/main/resources/static
        cp ${targetPath}/admin-*-web/dist/* ${targetPath}/koca-admin-standalone-*-bootapp/src/main/resources/static
    """
}

def setServiceConfig(String targetPath) {
    // auth.yml调整
    sh """
        cd ${targetPath}/pgk/conf/config/
cat >> auth.yml <<EOF
        - /js/**
        - /*.js
        - /*/*.js
        - /*.css
        - /css/**
        - /img/**
        - /fonts/**
        - /error/**
        - /config.json
        - /*.html
        - /*.png
        - /*.gz
EOF        
        cd -
    """
}

def startServer(String targetPath){
    sh """
        cd  ${targetPath}/pkg
        sh shutdown.sh
        sh startup.sh
        cd -
    """
}



/**
 * 制作创建web工程脚本
 * project :项目对象
 * vueVersion:vue的版本
 * env:环境,develop,test,master
 */ 
def makeWebCmdAndSh(def project,String vueVersion,String env,String targetPath){

    // 框架名
    def archetypeName
    // 框架版本
    def archetypeVersion
    for(item in project.webs.archetypeAndUi) {
        if(item.env == env) {
            archetypeName = item.archetype.name
            archetypeVersion = item.archetype.version
            break
        }
    }

    // 模块列表
    def modulesStr=""
    for(i in project.webs.modules) {
        println("i:"+i) 
        modulesStr += i + ","
        println("modulesStr:"+modulesStr) 

    }
    
    def preset
    if(vueVersion == "v2") {
        preset = "2"
    } else {
        preset = "3"
    }

//写sh脚本,注脚本包含EOF,脚本前面不能有空格
sh """
#! /bin/bash
cat>admin-msa-create-web-${vueVersion}.sh<<EOF
npm install @szkingdom.koca/cli -g --force 
kc create admin-${vueVersion}-web --archetype=${archetypeName} --version ${archetypeVersion} --modules=${modulesStr} --preset=${preset}
EOF
"""

//写bat脚本
sh """
#! /bin/bash
cat>admin-msa-create-web-${vueVersion}.bat<<EOF
@echo off
call npm install @szkingdom.koca/cli -g --force 
call kc create admin-${vueVersion}-web --archetype=${archetypeName} --version ${archetypeVersion} --modules=${modulesStr} --preset=${preset}
EOF
"""

// 拷贝到指定目录
sh """
    rm -rf ${targetPath}
    mkdir -p ${targetPath}
    mv admin-msa-create-web-${vueVersion}.sh  ${targetPath}
    mv admin-msa-create-web-${vueVersion}.bat  ${targetPath}
"""
}

/**
 * 连接npm仓库
 * npmUrl: npm仓库url 如:http://10.202.63.20:8081/repository/koca-npm/
 * userName: 用户名
 * passWord: 密码  
 */ 
def loginNexus(String npmUrl, String userName, String passWord){
sh """
#!/bin/bash
npm config set registry ${npmUrl}
expect <<EOF
    set timeout 10
    spawn npm login ${npmUrl}
    expect {
        "Username: " { 
            send "${userName}\r"; 
            exp_continue 
        }
        "Password: " { 
            send "${passWord}\r"; 
            exp_continue 
        }
        "Email: (this IS public) " {
            send "koca@szkingdom.com\r"; 
            exp_continue 
        }
    }
EOF
"""
}

/**
 * 制作web工程
 * vueVersion: vue的版本
 * targetPath:交付资源的目录
 */
def makeWebProject(String vueVersion,String targetPath){
    if (vueVersion == "v2"){
        sh """
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"  # This loads nvm
            [ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion"
            sh /root/.nvm/nvm.sh
            nvm use 14
            node -v
            kc -v

            cd ${targetPath}
            chmod +x admin-msa-create-web-${vueVersion}.sh
            npm cache clean --force
            ./admin-msa-create-web-${vueVersion}.sh
            cd -
        """
    } else {
        sh """
            export NVM_DIR="$HOME/.nvm"
            [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"  # This loads nvm
            [ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion"
            sh /root/.nvm/nvm.sh
            nvm use 16
            node -v
            kc -v

            cd ${targetPath}
            chmod +x admin-msa-create-web-${vueVersion}.sh
            npm cache clean --force
            ./admin-msa-create-web-${vueVersion}.sh
            cd -
        """
    }

}

/**
 * 提供指定类型的数据脚本
 * sqlPathList: sql路径列表
 * dbType:数据库类型
 */
def getAllSql(def sqlPathList,String dbType,String sourceDbPath) {
    def paths = sqlPathList
    sh """
        rm -rf $sourceDbPath/all-sql
        mkdir -p $sourceDbPath/all-sql
    """
    if (paths != null) {
        for (path in paths) {
            def singlePath = path
            sh """
                for file in ` find $WORKSPACE/$singlePath -type f -name '*.sql' | grep 'ALL' `
                do 
                    echo Y |cp -f \$file $sourceDbPath/all-sql/
                done
            """
        }
    }
    sh """
        cd $sourceDbPath/all-sql
        for file in `ls `
        do
            mv \$file V0\${file#ALL}
        done
    """
    return "filesystem:$sourceDbPath/all-sql"
}

// 提取所有类型的数据库脚本
def makeFlywaySql(def project,String targetPath){
    for(fromDatabase in project.fromDatabases) {
        // 在目标路径下创建db/${fromDatabase.type}目录
        sh 'mkdir -p $targetPath/db/$fromDatabase.type'
        getAllSql(fromDatabase.sqlPath,fromDatabase.type,"$targetPath/db")
    }
}

// 调整web和bootapp的配置
def setConfig(String configPackage,String targetWebPath){
    if(configPackage == "单体-开发-v2"){
        // 修改前端配置vue.config.js
        //target: "http://10.202.63.4:7000/" => target: "http://127.0.0.1:8081/"
        sh """
            cd $targetWebPath/admin-v2-web
            sed -i "s/10.202.63.4/127.0.0.1/g" vue.config.js
            sed -i "s/7000/8081/g" vue.config.js
            cd -
        """

        // 修改config.json
        // admin/ => 空
        sh """
            cd $targetWebPath/admin-v2-web/public
            sed -i "s:admin/::g" config.json
            cd -
        """
    } else if (configPackage == "单体-开发-v3") {
        sh """
            cd $targetWebPath/admin-v3-web
            sed -i "s/10.202.63.5/127.0.0.1/g" .env.development
            sed -i "s/7000/8081/g" .env.development
            cd -
        """

        sh """
            cd $targetWebPath/admin-v3-web/config
            sed -i "s:admin/::g" config.json
            cd -
        """
    }
}


def switchJdbcDriver(String type) {
    if (type == 'oracle') {
        return 'oracle.jdbc.OracleDriver'
    }else if (type == 'mysql') {
        return 'com.mysql.cj.jdbc.Driver'
    }else if (type == 'tdsql') {
        return 'com.mysql.cj.jdbc.Driver'
    }else if (type == 'mssql') {
        return 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
    }else if (type == 'dm') {
        return 'dm.jdbc.driver.DmDriver'
    }
    return null
}

/**
 * 
 * 
 */
def execFlyway(String jdbcUrl, String userName, String passWord,String jdbcDriver,String sqlPath, Boolean clean) {
    if(clean) {
         sh "flyway -driver=$jdbcDriver -url='$jdbcUrl' -user=$userName -password=$passWord clean"
    }
    sh "flyway -locations=$sqlPath -driver=$jdbcDriver -url='$jdbcUrl' -user=$userName -password=$passWord -validateOnMigrate='false' migrate"
}


// 测试只能测试运行态,开发态不太好做测试验证
def testResource(Project project, String env, String dbType ,String targetPath) {
    // 首先执行数据库
    def jdbcMsg 
    for(item in project.fromDatabases) {
        if (item.type == dbType) {
            jdbcMsg = item.jdbc."${env}"
        }
    }

    if (jdbcMsg == null) {
        return "jdbcMsg is null"
    }  

    def url = jdbcMsg.jdbcUrl.replace("localhost","10.202.63.128")

    execFlyway(jdbcMsg.jdbcUrl,jdbcMsg.jdbcUsername,jdbcMsg.jdbcPassword,switchJdbcDriver(dbType),"${targetPath}+/db/${dbType}/all-sql",true)

    // 启动后台
    startServer(targetPath)

    // 打印访问链接
    println("访问链接:10.202.63.128:8081") 
}

/**
 * 制作admin单体开发态资源
 * project :项目对象
 * vueVersion: vue的版本
 * targetPath:资源生成的目录
 * env:环境,develop,test,master
 */ 
def makeAdminStandAloneDevelopResource(def project,String vueVersion, String env,String adminStandaloneBootAppPath, String targetPath){
    
    //1、生成前端工程脚本
    makeWebCmdAndSh(project,vueVersion,env,targetPath)
    //2、通过脚本生成前端工程 
    makeWebProject(vueVersion,targetPath)
    //3、拷贝后台工程
    def srcBootApp = "${adminStandaloneBootAppPath}/${vueVersion}"
    copyBootapp(vueVersion,srcBootApp,targetPath)
    //4、生成数据库脚本
    makeFlywaySql(project,targetPath)
    //5、拷贝readme
    def srcReadMePath = "${adminStandaloneBootAppPath}/${vueVersion}/develop"
    copyReadMe(srcReadMePath,targetPath)

}

// 制作admin单体运行态资源
def makeAdminStandAloneRuntimeResource(def project,String vueVersion, String env,String adminStandaloneBootAppPath, String targetPath){

   makeAdminStandAloneDevelopResource(project, vueVersion,  env, adminStandaloneBootAppPath,  targetPath)

   // 拷贝pgk
   def srcPkgPath = "${adminStandaloneBootAppPath}/${vueVersion}/runtime"
   copyPkg(srcPkgPath, targetPath)

   // 编译web
   def webPath = "${adminStandaloneBootAppPath}/${vueVersion}/runtime/admin-*-web"
   compileWeb(vueVersion, webPath)

   // 整合前端后台
   putWebDistToBooApp(targetPath)

   // 编译后台
   compileServer(targetPath)

   // jar包拷贝到pgk
   copyServerJarToPkg(targetPath)

   // 调整后台auth配置文件及数据库配置文件
   setServiceConfig(targetPath)

}

pipeline{

    agent{

        node{
            label 'Node10.202.63.20'
        }
    }

    parameters{
        string (defaultValue: '4.1.0', description: '最新版本号', name: 'koca_version')
        choice(description: '选择代码分支',name: 'defaultEnv',choices: ['develop','test','master'])
        choice(description: '选择vue版本',name: 'vue_version',choices: ['v2v3','v2','v3'])
        booleanParam (defaultValue: true, description: '制作ADMIN单体开发态交付包', name: 'admin_standalone_develop')
        booleanParam (defaultValue: true, description: '制作ADMIN单体运行态交付包', name: 'admin_standalone_runtime')
        booleanParam (defaultValue: true, description: '制作ADMIN微服务运行态交付包', name: 'admin_micro_runtime')
        choice(description: '选择调整配置的包',name: 'config_package',choices: ['all','单体-开发-v2','单体-运行-v2','单体-开发-v3','单体-运行-v3','mas-v2','msa-v3'])
        choice(description: '选择要测试的交付包',name: 'test_package',choices: ['all','单体-运行-v2','单体-运行-v3','mas-v2','msa-v3'])
        booleanParam (defaultValue: true, description: '上传到git', name: 'git_push_resource')
    }

    environment{
        // admin单体v2开发态资源生成路径
        adminv2Develop = '/opt/kdop/workspace/koca-admin-standalone-develop-v2-"${koca_version}"'
        // admin单体v2运行态资源生成路径
        adminv2Runtime = '/opt/kdop/workspace/koca-admin-standalone-runtime-v2-"${koca_version}"'
        // admin单体v3开发态资源生成路径
        adminv3Develop = '/opt/kdop/workspace/koca-admin-standalone-develop-v3-"${koca_version}"'
        // admin单体v3运行态资源生成路径
        adminv3Runtime = '/opt/kdop/workspace/koca-admin-standalone-runtime-v3-"${koca_version}"'
        // admin-standalone根路径
        adminStandalone = 'koca-application/admin-standalone'
        // admin-msa根路径
        adminMsa = 'koca-application/admin-msa'
        // 源仓库npm地址
        npmSourceUrl = 'http://10.200.0.5:8081/repository/npm-group/'
        // 源仓库用户名
        sourceUserName = 'zhaojiao'
        // 源仓库密码
        sourcePassword = 'Zj20301721$'
    }

    stages{

        stage('拉取代码'){

            steps{

                script{

                    // 下载bootapp
                    gitClone('http://xxx/KOCA/koca-application.git',"refs/heads/${defaultEnv}",'git-user','koca-application')
                    // 下载admin源代码,主要是获取数据库脚本
                    gitClone('http://xxx/KOCA/koca-admin.git',"refs/heads/${defaultEnv}",'git-user','koca-admin')
                    // 初始化对象
                    if("${params.vue_version}" == "v2"){
                        projectv2 = initProject("${adminMsa}/project.yaml")
                    }

                    else if ("${params.vue_version}" == "v3"){
                        projectv3 = initProject("${adminMsa}/project-v3.yaml")
                    }

                    else{
                        projectv2 = initProject("${adminMsa}/project.yaml")
                        projectv3 = initProject("${adminMsa}/project-v3.yaml")
                    }
                    // 登录npm仓库
                    loginNexus("${npmSourceUrl}","${sourceUserName}","${sourcePassword}")

                }
            }
        }

        stage('资源包制作'){

            parallel{

                stage('制作ADMIN单体开发态交付包'){

                    when{

                        expression{
                            return params.admin_standalone_develop
                        }
                    }

                    steps{

                        script{

                            if("${params.vue_version}" == "v2" || "${params.vue_version}" == "v2v3"){
                                // 制作v2
                                makeAdminStandAloneDevelopResource(
                                projectv2,
                                "v2",
                                "${defaultEnv}",
                                "${adminStandalone}",
                                "${adminv2Develop}")
                            }

                            if("${params.vue_version}" == "v3" || "${params.vue_version}" == "v2v3"){
                                // 制作v3
                                makeAdminStandAloneDevelopResource(
                                projectv3,
                                "v3",
                                "${defaultEnv}",
                                "${adminStandalone}",
                                "${adminv3Develop}")
                            }
                        }
                    }
                }

                stage('制作ADMIN单体运行态交付包'){

                    when{

                        expression{
                            return params.admin_standalone_runtime
                        }
                    }

                    steps{

                        script{

                            if("${params.vue_version}" == "v2" || "${params.vue_version}" == "v2v3"){
                                // 制作v2
                                makeAdminStandAloneRuntimeResource(
                                projectv2,
                                "v2",
                                "${defaultEnv}",
                                "${adminStandalone}",
                                "${adminv2Runtime}")
                            }

                            if("${params.vue_version}" == "v3" || "${params.vue_version}" == "v2v3"){
                                // 制作v3
                                makeAdminStandAloneRuntimeResource(
                                projectv3,
                                "v3",
                                "${defaultEnv}",
                                "${adminStandalone}",
                                "${adminv3Runtime}")
                            }
                        }
                    }
                }

                stage('制作ADMIN微服务运行态交付包'){

                    when{

                        expression{
                            return params.admin_micro_runtime
                        }
                    }

                    steps{
                        echo ''
                    }
                }
            }
        }

        stage('调整配置'){

            steps{

                script{

                    if("${params.config_package}" == "单体-开发-v2" || "${params.config_package}" == "all"){
                        setConfig("单体-开发-v2", "${adminv2Develop}")
                    }

                    if("${params.config_package}" == "单体-运行-v2" || "${params.config_package}" == "all"){
                        setConfig("单体-运行-v2", "${adminv2Runtime}")
                    }

                    if("${params.config_package}" == "单体-开发-v3" || "${params.config_package}" == "all"){
                        setConfig("单体-开发-v3", "${adminv3Develop}")
                    }

                    if("${params.config_package}" == "单体-运行-v3" || "${params.config_package}" == "all"){
                        setConfig("单体-运行-v3", "${adminv3Runtime}")
                    }

                    if("${params.config_package}" == "mas-v2"){
                        
                    }

                    if("${params.config_package}" == "msa-v3"){
                        
                    }
                }
            }
        }

        stage('资源包测试'){

            steps{

                script{

                    //def testResource(Project project, String env, String dbType ,String targetPath)
                    if("${params.test_package}" == "单体-运行-v2" || "${params.test_package}"== "all"){
                        testResource(projectv2, "${params.defaultEnv}", "mysql", "${adminv2Runtime}")
                    }

                    if("${params.test_package}" == "单体-运行-v3" || "${params.test_package}"== "all"){
                        testResource(projectv3, "${params.defaultEnv}", "mysql", "${adminv3Runtime}")
                    }
                }
            }
        }

        stage('push到git仓库'){

            steps{
                echo ''
            }
        }
    }
}