Nexus-CI-[流水线插件集成|手动上传|自动上传]

root
233
文章
0
评论
2021年10月22日18:59:59 评论 13463字阅读44分52秒

Nexus-CI-[流水线插件集成|手动上传|自动上传]

在开始引入制品的时候,就应该制定制品库的管理和使用规范。 有了标准化的规范之后, 就很容易实现自动化。(为什么有些工作无法做成自动化? -无标准)

 

约定制品规范

1.版本号

  • 主版本号:表示项目的重大架构变更。
  • 次版本号:表示较大范围的功能增加和变化。
  • 修订版本号:表示重大Bug的修复。
  • 里程碑版本:表示某一个版本的里程碑。

2.仓库命名

类型

格式

示例

仓库组

<技术>-group

maven-group

仓库

<业务简称>-<技术>-<类型>

devops-maven-RELEASE

制品

<应用名称>-<版本号>

demo-devops-service-1.1.0.jar

3.目录结构: 按照 业务/服务/版本 层级。

使用maven指令上传制品

参考:https://support.sonatype.com/hc/en-us/articles/213465818-How-can-I-programmatically-upload-an-artifact-into-Nexus-2-

上传制品之前, 肯定得确定目标仓库是存在的。 如果不存在我们可以新建一个 hosted类型的maven仓库。

仓库已经有了, 需要更新maven的配置文件,在settings.xml中添加仓库的认证信息。如下:

    <mirror>
      <id>hwf-maven</id>
      <mirrorOf>*</mirrorOf>
      <name>maven repo</name>
      <url>http://192.168.1.110:8081/nexus/repository/maven-releases/</url>
    </mirror>

注意使用mvn deploy 发布时,-DrepositoryId参数的值要与上面配置文件中的<server>标签中的<id>一致。不然会出现401,用户认证失败的问题。

mvn deploy:deploy-file
-DgroupId=xxxxxx pom中的groupId
-DartifactId=xxxxxx pom中的artifactId
-Dversion=xxxxxx pom中的版本号version
-Dpackaging=xxxxxx pom中打包方式
-Dfile=xxxxxx 本地文件
-Durl=xxxxxx 仓库url
-DrepositoryId=xxxxxx 对应的是setting.xml(认证)

Maven上传报错, 401 可以确定是认证的错误。 需要检查认证信息。

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy-file (default-cli) on project standalone-pom: Failed to deploy artifacts: Could not transfer artifact wlmqpacx.app:wlmqpacx-app:jar:1.0 from/to remote-repository (http://192.168.1.110:8081/nexus/repository/hwf-maven-release/): authentication failed for http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/wlmqpacx-app/1.0/wlmqpacx-app-1.0.jar, status: 401 Unauthorized -> [Help 1]

在maven的settings.xml文件中添加server字段添加认证信息//id为仓库名称

    <server>
        <id>wlmqpacx<id>
        <username>admin</username>
        <password>admin123</password>
    </server>

m命令执行添加认证名称

mvn deploy:deploy-file \
-DgroupId=wlmqpacx.app \
-DartifactId=app-test \
-Dversion=1.0 \
-Dpackaging=jar \
-Dfile=demo/target/demo-0.0.1-SNAPSHOT.jar \
-Durl=http://192.168.1.110:8081/nexus/repository/hwf-maven-release \
-DrepositoryId=wlmqpacx

 

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- maven-deploy-plugin:2.7:deploy-file (default-cli) @ standalone-pom ---
Uploading to wlmqpacx: http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/app-test/1.0/app-test-1.0.jar
Uploaded to wlmqpacx: http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/app-test/1.0/app-test-1.0.jar (22 B at 124 B/s)
Uploading to wlmqpacx: http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/app-test/1.0/app-test-1.0.pom
Uploaded to wlmqpacx: http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/app-test/1.0/app-test-1.0.pom (392 B at 10 kB/s)
Downloading from wlmqpacx: http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/app-test/maven-metadata.xml
Uploading to wlmqpacx: http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/app-test/maven-metadata.xml
Uploaded to wlmqpacx: http://192.168.1.110:8081/nexus/repository/hwf-maven-release/wlmqpacx/app/app-test/maven-metadata.xml (296 B at 8.0 kB/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.908 s
[INFO] Finished at: 2021-10-20T17:18:51+08:00
[INFO] ------------------------------------------------------------------------

 

直接读取pom文件(方便)

mvn deploy:deploy-file \
-DgeneratePom=false \
-DrepositoryId=wlmqpacx \
-Durl=http://192.168.1.110:8081/nexus/repository/hwf-maven-release \
-DpomFile=pom.xml \
-Dfile=target/demo-0.0.1-SNAPSHOT.jar

 

自定义pom信息(灵活)

mvn deploy:deploy-file -Dmaven.test.skip=true  \
-Dfile=target/demo-0.0.1-SNAPSHOT.jar \
-DgroupId=wlmqpacx.app \
-DartifactId=app-test \
-Dversion=1.1 \
-Dpackaging=jar \
-DrepositoryId=wlmqpacx \
-Durl=http://192.168.1.110:8081/nexus/repository/hwf-maven-release

 

FAQ:

release类型的仓库只能上传release版本的包。如果你尝试用snapshot包上传到release类型的仓库时会遇到这些错误的。

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy-file (default-cli) on project demo: Failed to deploy artifacts: Could not transfer artifact com.example:demo:jar:0.0.1 from/to maven-hosted (http://192.168.1.200:8081/repository/maven-zeyang-test/): transfer failed for http://192.168.1.200:8081/repository/maven-zeyang-test/com/example/demo/0.0.1/demo-0.0.1.jar, status: 400 Repository version policy: SNAPSHOT does not allow version: 0.0.1 -> [Help 1]

解决方法: 1. 更新pom中的版本号 2. 对号入座,上传到对应类型的仓库。

<groupId>com.example</groupId>
<artifactId>myapp</artifactId>
<version>0.0.2-SNAPSHOT</version>    //改成0.0.2-RELEASE

将包上传到snapshot类型的仓库:

mvn deploy:deploy-file -Dmaven.test.skip=true  \
-Dfile=target/demo-0.0.1-SNAPSHOT.jar \
-DgroupId=wlmqpacx.app \
-DartifactId=app-test \
-Dversion=1.1  \
-Dpackaging=jar \
-DrepositoryId=wlmqpacx \
-Durl=http://192.168.1.110:8081/nexus/repository/hwf-maven-release

 

使用Jenkins插件上传制品

安装Nexus Artifact Uploader插件、使用片段生成器生成DSL。[了解就行]

如下面代码:

nexusArtifactUploader artifacts: [[artifactId: 'wlmqpacx', 
                                   classifier: '',
                                   file: 'target/demo-0.0.1-SNAPSHOT.jar', 
                                   type: 'jar']],
                                        credentialsId: '8a3c99b1-a165-4ac6-a972-2355e6cc14a7',
                                        groupId: 'wlmqpacx-app',
                                        nexusUrl: 'http://192.168.1.110:8081/nexus',
                                        nexusVersion: 'nexus3',
                                        protocol: 'http',
                                        repository: 'app-test',
                                        version: '1.0'

进行优化, 将参数以变量的方式传递给函数。【方法参考sonarqube传参】

//NexusUploadByPlugin('devops-test', 'target/demo-0.0.1-SNAPSHOT.jar', 'jar', 'com.jenkins','1.1.2')

def NexusUploadByPlugin(artifactId, file, type, groupId,version){
    nexusArtifactUploader   artifacts: [[artifactId: artifactId, 
                                    classifier: '', 
                                    file: file, 
                                    type: type]], 
                        credentialsId: '1de05a13-197c-4a72-8c6a-cd330fc45559', 
                        groupId: groupId, 
                        nexusUrl: '192.168.1.200:8081', 
                        nexusVersion: 'nexus3', 
                        protocol: 'http', 
                        repository: 'mymavenrepo', 
                        version: version
}

扩展: 可以在Jenkins页面添加参数, 让用户输入后进行发布。

@Library("mylib@main") _
import org.devops.*

def checkout = new Checkout()
def build = new Build()
def unittest = new UnitTest()
def sonar = new Sonar()

pipeline {
    agent { label "build" }

    options {
        skipDefaultCheckout true
    }


    stages{
        stage("Checkout"){
            steps{
                script {
                    println("GetCode")
                    checkout.GetCode("${env.srcUrl}", "${env.branchName}")
                }
            }
        }

        stage("Build"){
            steps{
                script{
                    println("Build")
                    sh "mvn clean package "
                }
            }
        }

        stage("UnitTest"){
            steps{
                script{
                    unittest.CodeTest("${env.buildTool}")
                }
            }
        }

        stage("Upload"){
            steps{
                script{
                    NexusUploadByPlugin("${env.artifactId}", 
                                        'target/demo-0.0.1-SNAPSHOT.jar', 
                                        "${env.type}", 
                                        "${env.groupId}",
                                        "${env.version}")
                }
            }
        }
    }
}

//NexusUploadByPlugin('devops-test', 'target/demo-0.0.1-SNAPSHOT.jar', 'jar', 'com.jenkins','1.1.2')

def NexusUploadByPlugin(artifactId, file, type, groupId,version){
    nexusArtifactUploader   artifacts: [[artifactId: artifactId, 
                                    classifier: '', 
                                    file: file, 
                                    type: type]], 
                        credentialsId: '1de05a13-197c-4a72-8c6a-cd330fc45559', 
                        groupId: groupId, 
                        nexusUrl: '192.168.1.110:8081', 
                        nexusVersion: 'nexus3', 
                        protocol: 'http', 
                        repository: 'mymavenrepo', 
                        version: version
}

如果是maven类型的具有源码的项目, 可以直接使用mvn命令上传,更加方便。

//上传制品使用maven命令
def PushArtifactsByMvn(repoName,filePath ){
    sh """
        mvn deploy:deploy-file \
            -DgeneratePom=false \
            -DrepositoryId="maven-hosted" \
            -Durl=http://192.168.1.110:8081/repository/"${repoName}" \
            -DpomFile=pom.xml \
            -Dfile="${filePath}"
    """
}

PushArtifactsByMvn("${params.repoName}","target/${pkg}")

 

我的流水线模板 

 Build.groovy

package hwf.devops


//Maven
def MavenBuild(){
    def buildTools = ["maven": "/data/apache-maven-3.8.3"]
    sh "${buildTools["maven"]}/bin/mvn clean package -DskipTests -f demo/pom.xml \
                        -s settings.xml"
}

//Gradle
def GradleBuild(){
    def buildTools = ["gradle": "/data/gradle-7.2"]
    sh "${buildTools["gradle"]}/bin/gradle clean && ${buildTools["gradle"]}/bin/gradle build -x test"
}

//Ant
def AntBuild(configPath="./build.xml"){
    sh "ant -f ${configPath}"
}

//Golang
def GoBuild(){
    def buildTools = ["go": "/data/go" ]
    sh "${buildTools["go"]}/bin/go build demo.go"
}

//Npm
def NpmBuild(){
    def buildTools = ["npm": "/data/node-v14.18.0-linux-x64" ]
    sh """
                    export PATH=\$PATH:${buildTools["npm"]}/bin
                    ${buildTools["npm"]}/bin/npm install
                    ${buildTools["npm"]}/bin/npm run build
    """
}

//Yarn
def YarnBuild(){
    sh "yarn install && yarn build "
}

//Main
def CodeBuild(type){
    switch(type){
        case "maven":
            MavenBuild()
            break;
        case "gradle":
            GradleBuild()
            break;
        case "npm":
            NpmBuild()
            break;
        case "yarn":
            YarnBuild()
            break;
        default:
            error "No such tools ... [maven/ant/gradle/npm/yarn/go]"
            break
    }
}

 

Checkout.groovy

package hwf.devops
//下载代码
 def GetCode(srcUrl, branchName){
    checkout([$class: 'GitSCM', 
            branches: [[name: branchName]], 
            extensions: [], 
            userRemoteConfigs: [[
            credentialsId: 'gitlab-root', 
            url: srcUrl]]])
}

 

Nexuspackage.groovy

package hwf.devops
//nexusupload

def Upload(artifaceId,file,type,groupId,repository,version){
     nexusArtifactUploader artifacts: [[artifactId: artifaceId, 
                                        classifier: '', 
                                        file: file, 
                                        type: type]], 
                                        credentialsId: '8a3c99b1-a165-4ac6-a972-2355e6cc14a7', 
                                        groupId: groupId, 
                                        nexusUrl: '192.168.1.110:8081/nexus', 
                                        nexusVersion: 'nexus3', 
                                        protocol: 'http', 
                                        repository: repository, 
                                        version: version
}

 

 Sonar.groovy

package hwf.devops

def SonarRequest(apiUrl,method){
    withCredentials([string(credentialsId: "16ed65f2-1b1e-4fbb-b976-a5fd60698d60", variable: 'SONAR_TOKEN')]) {
        sonarApi = "http://192.168.1.110:9000/api"
        response = sh  returnStdout: true, 
            script: """
            curl --location \
                 --request ${method} \
                 "${sonarApi}/${apiUrl}" \
                 --header "Authorization: Basic ${SONAR_TOKEN}"
            """
        // json格式化
        try {
            response = readJSON text: """ ${response - "\n"} """
        } catch(e){
            response = readJSON text: """{"errors" : true}"""
        }
        return response
        
    }
}

//查找项目
def SearchProject(projectName){
    apiUrl = "projects/search?projects=${projectName}"
    response = SonarRequest(apiUrl,"GET")
    if (response.paging.total == 0){
        return false
    }
    return true 
}


//创建项目
def CreateProject(projectName){
    apiUrl = "projects/create?name=${projectName}&project=${projectName}"
    response = SonarRequest(apiUrl,"POST")
    try{
        if (response.project.key == projectName ) {
            println("Project Create success!...")
            return true
        }
    }catch(e){
        println(response.errors)
        return false
    }
}

// 更新质量阈
def UpdateQualityProfiles(lang, projectName, profileName){
    apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${profileName}"
    response = SonarRequest(apiUrl,"POST")
    
    if (response.errors != true){
        println("ERROR: UpdateQualityProfiles ${response.errors}...")
        return false
    } else {
        println("SUCCESS: UpdateQualityProfiles ${lang} > ${projectName} > ${profileName}" )
        return true
    }
}

def SonarJava(projectName, groupName ){
    withCredentials([string(credentialsId: '9a2fd415-eebb-403b-9116-db07f9ae2605', variable: 'AUTH_TOKEN')]) {
        sh """
            sonar-scanner -Dsonar.host.url=http://192.168.1.110:9000 \
                -Dsonar.projectKey=${projectName} \
                -Dsonar.projectName=${projectName} \
                -Dsonar.projectVersion=${BUILD_ID} \
                -Dsonar.login=${AUTH_TOKEN} \
                -Dsonar.ws.timeout=30 \
                -Dsonar.projectDescription="my first project!" \
                -Dsonar.links.homepage=http://192.168.1.110:9080/${groupName}/${projectName} \
                -Dsonar.links.ci=http://192.168.1.110:8080/job/${groupName}/job/${projectName}/ \
                -Dsonar.sources=./demo/src \
                -Dsonar.sourceEncoding=UTF-8 \
                -Dsonar.java.binaries=./demo/target/classes \
                -Dsonar.java.test.binaries=./demo/target/test-classes 
        """
    }
}


def SonarWeb(projectName, groupName ){
    withCredentials([string(credentialsId: '9a2fd415-eebb-403b-9116-db07f9ae2605', variable: 'AUTH_TOKEN')]) {
        sh """
            sonar-scanner -Dsonar.host.url=http://192.168.1.110:9000 \
                -Dsonar.projectKey=${projectName} \
                -Dsonar.projectName=${projectName} \
                -Dsonar.projectVersion=${BUILD_ID} \
                -Dsonar.login=${AUTH_TOKEN} \
                -Dsonar.ws.timeout=30 \
                -Dsonar.projectDescription="my first project!" \
                -Dsonar.links.homepage=http://192.168.1.200/${groupName}/${projectName} \
                -Dsonar.links.ci=http://192.168.1.200:8080/job/${groupName}/job/${projectName}/ \
                -Dsonar.sources=src \
                -Dsonar.sourceEncoding=UTF-8 
        """
    }
}

//Main
def CodeSonar(type, projectName, groupName){
    if (SearchProject(projectName)){
        println("${projectName} exists....")
    } else {
        // 项目不存在
        println("${projectName} not found....")

        //创建项目
        CreateProject(projectName)
    }
    //质量配置
    profileMap = ["maven": "java", "npm": "js"]
    UpdateQualityProfiles(profileMap[type], projectName, groupName)

    switch(type){
        case "maven":
            
            SonarJava(projectName, groupName)
            break;
        case "gradle":
            SonarJava(projectName, groupName)
            break;
        case "npm":
            SonarWeb(projectName, groupName)
            break;
        default:
            println("No such tools ... [maven/ant/gradle/npm/yarn/go]")
            break
    }
}

 

UnitTest.groovy

package hwf.devops

//Maven
def MavenTest(){
    def buildTools = ["maven": "/data/apache-maven-3.8.3"]
    sh """
    ${buildTools["maven"]}/bin/mvn test -f demo/pom.xml -s settings.xml

    """
}

//Gradle
def GradleTest(){
    def buildTools = ["gradle": "/data/gradle-7.2"]
    sh """
        ${buildTools["gradle"]}/bin/gradle test
      junit 'build/test-results/test/*.xml'
    """
}

//Ant
//def AntBuild(configPath="./build.xml"){
//    sh "ant -f ${configPath}"
//}

//Golang
//def GoTest(){
    //sh " go test"
//}

//Npm
def NpmTest(){
    def buildTools = ["npm": "/data/node-v14.18.0-linux-x64" ]
    sh """
            export PATH=\$PATH:${buildTools["npm"]}/bin
            ${buildTools["npm"]}/bin/npm test"
    """
}

//Yarn
//def YarnTest(){
//    sh "yarn test "
//}

//Main
def CodeTest(type){
    switch(type){
        case "maven":
            MavenTest()
            break;
        case "gradle":
            GradleTest()
            break;
        default:
            println("No such tools ... [maven/ant/gradle/npm/yarn/go]")
            break
    }
}

 

jenkinsfile

@Library("hwf@main") _    

import hwf.devops.*           // 导入库

def checkout = new Checkout()
def build = new Build()
def unittest = new UnitTest()
def sonar = new Sonar()
def nexuspackage =  new Nexuspackage()

pipeline {
    agent { label "build" }

    stages{
        stage("Checkout"){
            steps{
                script {
                    println("GetCode")
                    checkout.GetCode("${env.srcUrl}", "${env.branchName}")
                }
            }
        }

        stage("Build"){
            steps{
                script{
                    println("Build")
                    build.CodeBuild("${env.buildTool}")
                }
            }
        }

        stage("Nexuspackage"){
            steps{
                script{
                    nexuspackage.Upload("${env.artifaceId}",
                                        "${env.file}",
                                        "${env.type}",
                                        "${env.groupId}",
                                        "${prository}",
                                        "${version}")
                    //nexuspackage.Upload('app-test','./demo/target/demo-0.0.1-SNAPSHOT.jar','jar','wlmqpacx.app','wlmqpacx','1.11')

                }
            }
        }

        stage("UnitTest"){
            steps{
                script{
                    unittest.CodeTest("${env.buildTool}")
                }
            }
        }

        stage("SonarScan"){
            steps {
                script{
                    groupName = "${JOB_NAME}".split("/")[0]
                    projectName = "${JOB_NAME}".split("/")[-1] //devops03/devops03-maven-service
                    sonar.CodeSonar("${env.buildTool}", projectName, groupName)

                }
            }
        }

    }
}

 

 

继续阅读
weinxin
我的微信
这是我的微信扫一扫
  • 文本由 发表于 2021年10月22日18:59:59
  • 除非特殊声明,本站文章均为原创,转载请务必保留本文链接
Nexus-[功能简介|容器方式安装|使用方法] Nexus

Nexus-[功能简介|容器方式安装|使用方法]

Nexus- 工作流定义: 集成流水线: 提交代码,构建,单测,代码扫描,上传制品【生成制品】 制品晋级流水线:输入版本,选择晋级策略。(将制品复制到对应环境的仓库) 发布流水线: 输入版本号, 输入...
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: