Wedge
The last article solved the requirement of automatic triggering of submit / merge requests, but all front-end modules are in the same code warehouse. How to obtain the change file path and determine which module to publish? This article will take you to solve this problem.
thinking
Solve three problems respectively:
- Get a list of changed files
- Determine the module according to the file list
- Build and publish scripts
process
The GitLab event triggered Jenkins construction is just a start signal. To obtain the list of change files, we need to know the version number of a warehouse during the last construction. Here, Jenkins plug-in git plugin has helped us realize this work. Therefore, you only need to check out the code through git plugin.
Check out code
checkout([ $class: 'GitSCM', branches: [[name: "*/$branchName"]], doGenerateSubmoduleConfigurations: false, extensions: [ [$class: 'RelativeTargetDirectory', relativeTargetDir: "$relativeTarget"] ], submoduleCfg: [], userRemoteConfigs: [ [credentialsId: "$credentialsId", url: "$gitUrl"] ] ])
Please replace $branchName as the branch name, $relativeTarget as the check-out relative path, $credentialsId as the user credentials and $gitUrl as the GIT warehouse address.
Get change file list
//Get the list of changed files and return to HashSet. Note that the added affected file path does not contain the warehouse directory name @NonCPS def getChangeFilePathSet() { def changedFiles = new HashSet<String>(); echo "Start getting the list of changed files" for (int i = 0; i < currentBuild.changeSets.size(); i++) { def entries = currentBuild.changeSets[i].items for (int j = 0; j < entries.length; j++) { def entry = entries[j] changedFiles.addAll(entry.getAffectedPaths()); } } println 'Output modified file list:' + changedFiles return changedFiles; }
This method can be placed outside the pipeline block and directly referenced in the script block. The implementation idea is to access currentBuild.changeSets to obtain the change list of this build compared with the last build. The HashSet is returned for convenience, and other containers can also be used.
Note: each file in the changed file list is the path relative to its warehouse!
Change the file list truncation string, obtain the module list and remove the duplicate
//Gets the set set of the automatic publishing module at the front end of the consolidated report. //pathPrefix is the module path prefix, such as develop/@gc @NonCPS def getAutoPublishModuleSet(pathPrefix) { //Use the Set container to remove the weight and ensure that there is only one module to be released def modulePaths = new HashSet<String>(); for(def filePath in getChangeFilePathSet()){ //Ignore files that are not front-end modules, such as Jenkinsfile if(filePath.startsWith(pathPrefix)){ //Gets the position of the next / starting from the subscript that exceeds the length of the module prefix. String position int index = filePath.indexOf('/', pathPrefix.length()+1) //Get the module path by string, such as develop/@gc/test def modulePath = filePath.substring(0, index) println 'add module path: ' + modulePath modulePaths.add(modulePath) } } println 'Output the list of modules to be released:' + modulePaths return modulePaths; }
Write a build publish Shell script
publish-web-module.sh
#!/bin/bash #This script is used to build the publishing front-end module, @ author: Hellxz #$1: release version / $2: module directory set -eu echo "------------Start publishing $2 modular------------>" cd $2 echo "clear dist node_modules package-lock.json ......" rm -rf dist node_modules package-lock.json echo "Installing dependencies" npm i echo "Start building" npm run build:dev echo "Start publishing" npm --no-git-tag-version version $1 npm publish echo "<------------release $2 Module complete------------" cd ${WORKSPACE}/web; #Back to the front-end source directory exit 0;
Loop call build publish script
for(def modulePath in modulePaths){ sh label: "Build release front end module ${publishVersion} ${modulePath}", script: "bash ${SHELL_PATH}/publish-web-module.sh ${publishVersion} ${modulePath}" }
Pipeline example
Jenkinsfile
pipeline{ agent any; environment{ gitUrl="http://xxxxxxxx/xxxx/web.git" branchName=dev relativeTarget="web" credentialsId=credentials('git-user') pathPrefix="develop/@gc" publishVersion="v1.0" npmRepo="http://xxxxxx/nexus/repository/npm-public/" npmToken=credentials('npm-token') } stages{ stage("Check out code"){ steps{ script { cleanWs() checkoutRepo("master", "jenkins", "${credentialsId}", "http://xxxxxxxx/xxxx/jenkins.git") checkoutRepo("${branchName}", "${relativeTarget}", "${credentialsId}", "${gitUrl}") } } } stage("Build release"){ steps{ script{ sh label: "set up npm Warehouse", script: "npm set registry ${npmRepo}" sh label: "Sign in npm Warehouse", script: "npm config set //xxxxxx/nexus/repository/npm-public/:_authToken ${npmToken}" def modulePaths = getAutoPublishModuleSet(env.pathPrefix) for(def modulePath in modulePaths){ sh label: "Build release front end module ${publishVersion} ${modulePath}", script: "bash ${SHELL_PATH}/publish-web-module.sh ${publishVersion} ${modulePath}" } } } post{ script{ cleanWs() } } } } } //Method of extracting check-out code @NonCPS def checkoutRepo(branchName, relativeTarget, credentialsId, gitUrl){ checkout([ $class: 'GitSCM', branches: [[name: "*/$branchName"]], doGenerateSubmoduleConfigurations: false, extensions: [ [$class: 'RelativeTargetDirectory', relativeTargetDir: "$relativeTarget"] ], submoduleCfg: [], userRemoteConfigs: [ [credentialsId: "$credentialsId", url: "$gitUrl"] ] ]) } //Get the list of changed files and return to HashSet. Note that the added affected file path does not contain the warehouse directory name @NonCPS def getChangeFilePathSet() { def changedFiles = new HashSet<String>(); echo "Start getting the list of changed files" for (int i = 0; i < currentBuild.changeSets.size(); i++) { def entries = currentBuild.changeSets[i].items for (int j = 0; j < entries.length; j++) { def entry = entries[j] changedFiles.addAll(entry.getAffectedPaths()); } } println 'Output modified file list:' + changedFiles return changedFiles; } //Gets the set set of the automatic publishing module at the front end of the consolidated report. @NonCPS def getAutoPublishModuleSet(pathPrefix) { //Use the Set container to remove the weight and ensure that there is only one module to be released def modulePaths = new HashSet<String>(); for(def filePath in getChangeFilePathSet()){ //Ignore files that are not front-end modules, such as Jenkinsfile if(filePath.startsWith(pathPrefix)){ //Gets the position of the next / starting from the subscript that exceeds the length of the module prefix. String position int index = filePath.indexOf('/', pathPrefix.length()+1) //Get the module path by string, such as develop/@gc/test def modulePath = filePath.substring(0, index) println 'add module path: ' + modulePath modulePaths.add(modulePath) } } println 'Output the list of modules to be released:' + modulePaths return modulePaths; }
It's just for reference. I put the extracted methods into the shared library and write scripts more clearly and briefly.
Any questions
- The submission record will not be recognized during the first build, and may be missed once
- If you cut to a branch that has not been built, it will also be missed once
- Limited to the length of the article, the function of manually transmitting parameters to the specified module is not added
For the problem of missing distribution detected by multiple branches for the first time, this is because there is no reference to the same branch submission ID for reference. It is not a technical problem in itself. All front-end distribution branches are submitted in advance. As long as the construction is triggered, there will be no missing distribution in the future.
last
I hope it can inspire you. If you have a more elegant implementation or there are mistakes in the article, I hope you can comment and point out. Thank you.
This article is published in blog Park (northeast little fox) https://www.cnblogs.com/hellxz/ )And CSDN (northeast little fox hellxz) https://blog.csdn.net/u012586326 )Reprint is prohibited.