目的
- 实现后台java的maven部署
- 实现前端npm的部署
准备
-
两台服务器,我这边都是windows的:
创新互联建站是一家以网站建设公司、网页设计、品牌设计、软件运维、成都网站推广、小程序App开发等移动开发为一体互联网公司。已累计为VR全景等众行业中小客户提供优质的互联网建站和软件开发服务。
- 服务器A,用于安装jenkins等服务
- 服务器B,待部署机器
-
Jenkins,除了默认插件外,额外需要手动安装插件:
- Blue Ocean,更方便的展示进度等
- Publish Over SSH,用于通过ssh来部署远程服务器
- DingTalk,钉钉机器人通知插件
-
OpenSSH
-
Git
-
其他的
java
、maven
、npm
等工具
安装软件
- 在
服务器A
中安装jenkins
,由于我这边还是旧的windows server 2012
,对docker
支持不好,所以直接安装的msi文件,具体安装步骤参考官方文档,安装完成后再安装上述的几个插件。 - 在
服务器A
安装Git
,方便从github等代码工具中远程拉取代码,具体安装步骤可以自行网上搜索,由于我们后期会用到ssh
和tar
等工具,所以需要将安装目录\Git\usr\bin
此路径加入到windows环境变量中,这样就可以用里面的各种工具了,如果是npm项目,需要在服务器B
中也要安装,主要是为了用tar
打包命令,如果用其他打包方式也可以不安装。 - 在
服务器A
安装java
、maven
、npm
,最好与开发服务上版本保持一致,并将其加入到windows环境变量中,这样的话jenkins
就可以直接使用。 - 在
服务器B
安装openssh
,安装流程查看官方文档:Install Win32 OpenSSH,同样需要将此路径加入环境变量,且需要按照文档开启端口、开机自启动等
ssh密钥联通
-
整体的流程就是
服务器B
相当于服务端,服务器A
相当于客户端,我们需要用客户端通过ssh链接到服务端,然后传输部署的文件过去,所以需要在客户端中生成私钥和公钥,公钥会给到服务端中,私钥则还是留在客户端,这样ssh链接时通过私钥和公钥验证通过链接到一起就可以传输文件了。 -
在
服务器A
生成密钥,需要注意的是jenkins
的Publish Over SSH
不支持最新的密钥格式,只支持旧的pem格式的,所以需要加一些参数才行,在刚安装的git命令工具中输入ssh-keygen -m PEM -t rsa -b 4096
,按照提示一步步执行,生成的会放在~/.ssh
文件下:xxx_rsa #私钥 xxx_rsa.pub #公钥
-
在
服务器B
可以先启动一下openssh
服务然后关闭,此时会自动生成C:\Program Data\ssh
目录,然后我们配置此目录下的sshd_config
文件,改动如下:PubkeyAcceptedKeyTypes=+ssh-rsa #由于上方说了用的旧的格式密钥,新版本默认已不支持了,所以这里需要额外配置增加支持 PubkeyAuthentication yes #原先是注释来着,打开并设置为yes,表示开启密钥验证 PasswordAuthentication no #原先注释来着,打开并设置为no, 关闭密码验证,否则不安全
-
将
服务器A
生产的公钥放到服务B
中,这里需要注意,服务器B
的用户是管理员用户,则需要放到C:\ProgramData\ssh\administrators_authorized_keys
文件中,如果是普通用户,则需要放到C:\Users\用户名\.ssh\authorized_keys
文件中,通过这里我们也可以发现密钥实际上是和用户名没有关系的,放到哪个用户名下,是根据位置来的,如果这个用户有权限访问到这个密钥实际上就是可以用这个用户名来登陆的。 -
测试联通性,可以在
服务器A
的~/.ssh/config
中配置:Host b_name #服务器B随便起个名字 HostName 192.168.0.31 #服务器B的IP地址 IdentityFile ~/.ssh/xxx_rsa #自身生成的私钥 User administrator #服务器B的登陆用户名 Port 22 #没改端口的话默认22 ServerAliveInterval 60
然后可以
ssh b_name
来测试是否可以联通 -
在
jenkins
的Publish Over SSH
插件配置中并测试联通性,位置Manage Jenkins
->Configure System
->SSH Servers
中:点击测试,看是否联通成功,如果出现类似
Fail Auth
等错误,可以参考此解决方法来解决:Jenkins Publish over ssh authentification failed with private key
git 密钥联通
- 同上在
服务器A
中同上创建私钥和公钥,但是github只支持最新版本的,可以不用加那些参数了,具体参考官方文档:新增 SSH 密钥到 GitHub 帐户 - GitHub Docs - 以github为例,在个人主页的
Setting
->SSH AND GPG keys
->SSH keys
中新增,将生成的公钥粘贴到github中的字段中就可以了 - 和上方一样来测试下联通是否OK,其他
gitee
等原理基本一样
maven项目部署
-
如果不熟悉
jenkins
的pipeline
相关的话,请先按照官方文档demo操作一遍:Build a Java app with Maven -
官方文档demo中都是用的docker,我这边没有,所以不太一样,而且官方文档没有回滚等操作,所以这边给出参考的
Jenkinsfile
:pipeline { agent any //没有用docker parameters {//这个是参数化构建 choice choices: ['deploy', 'rollback'], description: '', name: 'action' string description: 'rollback ID (only number)', name: 'version' } stages { stage('Build') { when {//如果是部署 expression { params.action == 'deploy' } } steps {//maven打包 bat 'mvn -B -DskipTests clean package'//linux下是用sh,windows下则bat } } stage('Archive') { when {//如果是部署 expression { params.action == 'deploy' } } steps {//将打包出来的jar包归档,方便回滚时用到 archiveArtifacts artifacts: '自身相关路径/target/*.jar', followSymlinks: false, onlyIfSuccessful: true } } stage('Rollback') { when {//如果是回滚 expression { params.action == 'rollback' } } steps {//回滚就不需要打包了,直接将原先版本的归档复制到打包出来的路径 bat 'xcopy /s /f /y "%JENKINS_HOME%\\jobs\\%JOB_NAME%\\builds\\%version%\\archive\\自身相关路径\\target" 自身相关路径\\target' } } stage('Publish') { steps {//publish over ssh插件相关参数,verbose为true,则jenkins_deploy.bat脚本的执行信息会返回 sshPublisher(publishers: [sshPublisherDesc(configName: '刚才设置的ssh的名称', sshRetry: [retries: 3, retryDelay: 5000], transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'cmd /c E:\\服务器B相关部署路径\jenkins_deploy.bat $BUILD_NUMBER', execTimeout: , flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '服务器B相关路径', remoteDirectorySDF: false, removePrefix: '自身相关路径/target', sourceFiles: '自身相关路径/target/*.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)]) } } } }
-
上方代码一些注解:
-
上方的
参数化构建
、归档
、publish over ssh
语法都是可以由可视化界面生成的,随便点开一个job后在左侧有流水线语法
这个选项,点开后页面在左侧Declarative Directive Generator
中选择parameters:Parameters
可以生成参数化构建片段;而左侧片段生成器
中archiveArtifacts archive the artifacts
用来生成归档片段,sshPublishers: Send build artifacts over SSH
则用来生成发布的片段,这些具体的使用,可以参考官方文档也可以自行搜索更详细的用法文章。 -
参数化构建如果在pipeline中写了后,不需要在界面中再配置,只需要运行一次后会自动从pipeline中获取,下次再构建就发现有参数需要填写了,要想回滚则选择
rollback
然后输入回滚的构建数字运行则会回滚: -
一些全局变量,可以参考官方文档:Using a Jenkinsfile,需要注意的是在linux中可以
$JENKINS_HOME
,但是在windows中就必须%JENKINS_HOME%
这样了,需要注意的是publish over ssh
给jenkins_deploy.bat
传递参数的$BUILD_NUMBER
则还是用$
才行,用%%
不起作用,且执行windows脚本时需要用cmd /c
开头。
-
-
服务器B
端的结构及脚本:-
项目结构:
abc: ├─backup │ └─test_2022_06_27__3.jar #在服务端也备份一份,格式:名称+日期+构建号+jar └─prod │ └─test.jar #生产文件 └─jenkins_deploy.bat
-
jenkins_deploy.bat
脚本:@echo off ::设置utf8编码运行 chcp ::移动到当前目录 cd /d E:\abc ::设置时间变量,需要注意的是utf编码和ansi编码所取时间的位数不一样 set "Ymd=%date:~3,4%_%date:~8,2%_%date:~11,2%_%time:~0,2%%time:~3,2%%time:~6,2%" ::将时间的空格用0补齐;将参数可能携带的引号去掉 set "param=%1" ::%Ymd: =0%是将空格转为0,%param:"=%是将"去掉 set backup_name=%Ymd: =0%_%param:"=% ::将现有的移到backup中 copy prod\test.jar backup\test_%backup_name%.jar echo 'prod中的备份到backup中' ::关闭服务 net stop test ::将最新的移动到生产目录中 move /y test.jar prod\test.jar echo '最新的移动到prod中' ::开启服务 net start test @echo on
-
-
上方脚本一些注释:
- jenkins编码没有做设置,所以要用utf8编码来执行bat脚本,否则在jenkins中的信息是乱码。
- 时间参数在
utf8
和ansi
中取值是不一样的,需要注意. 1%
是bat语法中第一个参数,就是上方的$BUILD_NUMBER
构建号,但传递过来可能后面带引号,例如2"
,所以要把"
也去掉%Ymd: =0%
意思是将其中的空格转为0,%param:"=%
意思是将其中的"
去掉- 需要先将
test.jar
改成用服务的方式运行,最好也要有优雅关闭,可以参考:spring boot不同版本的优雅关闭(graceful shutdown)和在windows下winsw服务方式运行的配置
npm项目部署
-
整体流程和maven一样,同样官方也有参考demo,Build a Node.js and React app with npm,这里只给出参考的文件:
-
Jenkinsfile
:pipeline { agent any parameters { choice choices: ['deploy', 'rollback'], description: '', name: 'action' string description: 'rollback ID (only number)', name: 'version' } stages { stage('Install') { when { expression { params.action == 'deploy' } } steps {//install bat 'npm ci --registry https://registry.npm.taobao.org' } } stage("Build"){ when { expression { params.action == 'deploy' } } steps {//build bat 'npm run build' } } stage("Archive"){ when { expression { params.action == 'deploy' } } steps {//先打包成压缩文件,再归档,同时也方便传输 bat 'tar -zcvf dist.tar.gz -C dist .' archiveArtifacts artifacts: '*.tar.gz', followSymlinks: false, onlyIfSuccessful: true } } stage('rollback') { when { expression { params.action == 'rollback' } } steps {//将压缩文件拷贝到正常打包后的位置 bat 'copy /y "%JENKINS_HOME%\\jobs\\%JOB_NAME%\\builds\\%version%\\archive\\dist.tar.gz" dist.tar.gz' } } stage("Publish"){ steps { sshPublisher(publishers: [sshPublisherDesc(configName: '刚才设置的ssh的名称', sshRetry: [retries: 3, retryDelay: 5000], transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'cmd /c E:\\服务器B相关部署路径\\jenkins_deploy.bat $BUILD_NUMBER', execTimeout: , flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '服务器B相关部署路径', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'dist.tar.gz')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)]) } } } }
-
服务器B的
jenkins_deploy.bat
脚本,结构和maven项目差不多。-
项目结构:
abc: ├─backup │ └─test_2022_06_27__3.tar.gz #在服务端也备份一份,格式:名称+日期+构建号+tar.gz └─prod │ ├─static │ └─index.html └─jenkins_deploy.bat
-
jenkins_deploy.bat
脚本:@echo off ::设置utf8编码运行 chcp ::移动到当前目录 cd /d E:\abc ::设置时间变量,需要注意的是utf编码和ansi编码所取时间的位数不一样 set "Ymd=%date:~3,4%_%date:~8,2%_%date:~11,2%_%time:~0,2%%time:~3,2%%time:~6,2%" ::获取第一个参数 set "param=%1" ::将时间的空格用0补齐;将参数可能携带的引号去掉 set backup_name=%Ymd: =0%_%param:"=% ::将现有的打包后移到backup中 tar -zcvf test_%backup_name%.tar.gz -C prod . move test_%backup_name%.tar.gz backup\test_%backup_name%.tar.gz echo 'prod中内容打包到backup中' ::清空prod文件夹,然后将传递过来的解压到prod中 del /q prod\* for /d %%x in (prod\*) do @rd /s /q "%%x" tar -zxvf dist.tar.gz -C prod echo '最新的解压到prod中' ::删除传递过来的 del dist.tar.gz echo '删除传递过来的文件' @echo on
-
构建通知
- 目前插件可以通过钉钉和企业微信机器人通知,目前只测试了钉钉的,感觉还可以,目前我这边没有在pipeline中自定义,只是用了通用功能,更多功能可查看官方文档或自行搜索相关文章。
完工
- 以上就是整体流程,只是记录了下一些关键点。
另外补充下小程序的部署和用powershell脚本的写法
-
小程序
-
主要是利用官方的miniprogram-ci来完成,此类库可以实现预览和上传(上传后还是需要登陆小程序平台来设置体验版或者是提交正式版本),这个类库是
nodejs
写的,所以需要大体了解下nodejs
脚本的写法,可以参考Node.js 入门教程 -
小程序用
miniprogram-ci
上传前需要先到小程序平台“开发管理”->"开发设置"->"小程序代码上传"中生成小程序代码上传密钥
,实际上就和ssh的密钥类似,在编写脚本时会用到此密钥,此密钥不要放到和代码一起的版本控制中,否则太不安全了,有两种方式,一种是直接放到jenkins所在服务器的某个路径,然后在脚本时直接引;一种是放到jenkins的密钥管理中,类似github的密钥一样,然后在pipeline
通过withCredentials
可以获取到,这里采用的是后一种方法,在jinkins
中新建credentials
,选择SSH Username with private key
,其中id
则为Jenkinsfile
中引用的名称,用户名可以随便填写,Private Key
则从小程序端下载的key文件中直接复制过来填入即可。 -
jenkins所在服务器安装
nodejs
(最好与开发的版本一致),同时在 jenkins插件管理中安装nodejs
插件并在全局配置中设置nodejs版本(安装插件后会多出此选项);需要在项目中引入miniprogram-ci
库:npm install miniprogram-ci --save
,项目结构如下所示,脚本放到ci\upload.js
下xxx: ├─ci │ └─upload.js #脚本路径 └─dist │ └─... └─public │ └─... └─src │ └─... └─JenkinsFile
-
upload.js
const ci = require('miniprogram-ci');//小程序类库 const path = require('path'); const fs = require("fs"); const argv = require('minimist')(process.argv.slice(2));//此类库主要用于解析参数,实现--version 12,则argv.version就为12,如果系统没有自带,则npm安装下 const manifest = require('../src/manifest.json');//用的uniapp,直接从这里取appid,需要确保manifest.json不要有注释,或者自己新建个json文件也行 const appDirectory = fs.realpathSync(process.cwd());//当前命令行路径,主要用于获取绝对路径 let projectPath = path.resolve(appDirectory, './dist/build/mp-weixin');//组装项目路径 let qrCodeImg = path.resolve(appDirectory, './qrcode.jpg');//组装二维码路径 let type = argv.type;//参数预览还是上传 let privateKeyPath = argv.key;//传递upload的私钥路径 let version = argv.version ? argv.version : argv.number;//版本号,如果有传递则用,没传递则用构建号 let desc = argv.desc ? argv.desc : '暂无描述';//描述 //配置 const project = new ci.Project({ appid: manifest["mp-weixin"].appid, type: 'miniProgram', projectPath: projectPath, privateKeyPath: privateKeyPath, ignores: ['node_modules/**/*'], }); if (type === 'preview') { //预览 (async () => { await ci.preview({ project, desc: desc, setting: { es6: true, es7: true }, qrcodeFormat: 'image', qrcodeOutputDest: qrCodeImg, onProgressUpdate: console.log, }); })(); } else if (type === 'upload') { //上传 (async () => { await ci.upload({ project, version: version, desc: desc, setting: { es6: true, es7: true }, onProgressUpdate: console.log, }); })(); }
-
JenkinsFile(cmd版本),小程序自带回退上一版本的功能,所以这里就没有做回退选项,如果想做可参考上方的实现,是同一个逻辑
pipeline { agent any parameters { string description: 'version (example: 1.0.0)', name: 'version' string description: 'description', name: 'desc' } stages { stage('Install') { steps { bat 'npm ci --registry https://registry.npm.taobao.org' } } stage("Build"){ steps { bat 'npm run build:mp-weixin'//用的uniapp } } stage("Preview"){ steps {//先掉用预览来生成二维码图片,用于归档后在jenkins中查看,这一步也可以不用 withCredentials([sshUserPrivateKey(credentialsId: '小程序密钥在jenkins保存后的id', keyFileVariable: 'identity')]) { bat 'node ci\\upload.js --type=preview --desc="%desc%" --key="%identity%"' } } } stage("Archive"){ steps {//同时将二维码也归档,方便在jenkins中查看,如果是jenkins外网可以访问,还可以将归档后的预览二维码发送到钉钉等通知工具中,或者内网也可以用oss自带的cli工具上传到oss中供外网访问,此二维码有效时间是25分钟 bat 'tar -zcvf dist.tar.gz -C dist\\build\\mp-weixin .' archiveArtifacts artifacts: '*.tar.gz,qrcode.jpg', followSymlinks: false, onlyIfSuccessful: true } } stage("Publish"){ steps {//上传,这里将version和BUILD_NUMBER都传递过去,如果version没有填写,则用构建号作为小程序版本号 withCredentials([sshUserPrivateKey(credentialsId: '小程序密钥在jenkins保存后的id', keyFileVariable: 'identity')]) { bat 'node ci\\upload.js --type=upload --version="%version%" --number="%BUILD_NUMBER%" --desc="%desc%" --key="%identity%"' } } } } }
-
jenkinsFile(powershell版本)
pipeline { agent any parameters { string description: 'version (example: 1.0.0)', name: 'version' string description: 'description', name: 'desc' } stages { stage('Install') { steps { powershell 'npm ci --registry https://registry.npm.taobao.org' } } stage("Build"){ steps { powershell 'npm run build:mp-weixin' } } stage("Preview"){ steps { withCredentials([sshUserPrivateKey(credentialsId: '小程序密钥在jenkins保存后的id', keyFileVariable: 'identity')]) { //这个参数中如果有空格会解析参数不完整,所以必须加引号 powershell "node ci\\upload.js --type=preview --desc='$desc' --key='$identity'" } } } stage("Archive"){ steps { powershell 'tar -zcvf dist.tar.gz -C dist\\build\\mp-weixin .' archiveArtifacts artifacts: '*.tar.gz,qrcode.jpg', followSymlinks: false, onlyIfSuccessful: true } } stage("Publish"){ steps { withCredentials([sshUserPrivateKey(credentialsId: '小程序密钥在jenkins保存后的id', keyFileVariable: 'identity')]) { powershell "node ci\\upload.js --type=upload --version='$version' --number='$BUILD_NUMBER' --desc='$desc' --key='$identity'" } } } } }
-
-
maven的powershell写法
-
jenkinsfiles
pipeline { agent any //没有用docker parameters {//这个是参数化构建 choice choices: ['deploy', 'rollback'], description: '', name: 'action' string description: 'rollback ID (only number)', name: 'version' } stages { stage('Build') { when {//如果是部署 expression { params.action == 'deploy' } } steps {//maven打包 powershell 'mvn -B -DskipTests clean package' } } stage('Archive') { when {//如果是部署 expression { params.action == 'deploy' } } steps {//将打包出来的jar包归档,方便回滚时用到 archiveArtifacts artifacts: '自身相关路径/target/*.jar', followSymlinks: false, onlyIfSuccessful: true } } stage('Rollback') { when {//如果是回滚 expression { params.action == 'rollback' } } steps {//回滚就不需要打包了,直接将原先版本的归档复制到打包出来的路径 powershell 'copy-item -path "$JENKINS_HOME\\jobs\\$JOB_NAME\\builds\\$version\\archive\\自身相关路径\\target\\*" -destination 自身相关路径\\target\\ -recurse -force' } } stage('Publish') { steps {//publish over ssh插件相关参数,verbose为true,则jenkins_deploy脚本的执行信息会返回 sshPublisher(publishers: [sshPublisherDesc(configName: '刚才设置的ssh的名称', sshRetry: [retries: 3, retryDelay: 5000], transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'powershell E:\\服务器B相关部署路径\jenkins_deploy.sp1 -number $BUILD_NUMBER', execTimeout: , flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '服务器B相关路径', remoteDirectorySDF: false, removePrefix: '自身相关路径/target', sourceFiles: '自身相关路径/target/*.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)]) } } } }
-
jenkins_deploy.ps1
#获取参数 param ( [string]$number ) #移动到当前目录 Set-Location E:\abc #设置时间变量 $date=(get-date).ToString('yyyy_MM_dd_HHmmss') #备份文件名 $backup_name = 'test_'+$date+'_'+$number+'.jar' #将现有的复制backup中 Copy-Item -path prod\test.jar -destination backup\$backup_name -force Write-Output 'backup end' #关闭服务 net stop test #将最新的移动到生产目录中 Move-Item -path test.jar -destination prod\test.jar -force Write-Output 'move new to prod' #开启服务 net start test Write-Output 'finished'
-
-
npm的powershell写法
-
jenkinsfiles
pipeline { agent any parameters { choice choices: ['deploy', 'rollback'], description: '', name: 'action' string description: 'rollback ID (only number)', name: 'version' } stages { stage('Install') { when { expression { params.action == 'deploy' } } steps {//install powershell 'npm ci --registry https://registry.npm.taobao.org' } } stage("Build"){ when { expression { params.action == 'deploy' } } steps {//build powershell 'npm run build' } } stage("Archive"){ when { expression { params.action == 'deploy' } } steps {//先打包成压缩文件,再归档,同时也方便传输 powershell 'tar -zcvf dist.tar.gz -C dist .' archiveArtifacts artifacts: '*.tar.gz', followSymlinks: false, onlyIfSuccessful: true } } stage('rollback') { when { expression { params.action == 'rollback' } } steps {//将压缩文件拷贝到正常打包后的位置 powershell 'copy-item -path "$JENKINS_HOME\\jobs\\$JOB_NAME\\builds\\$version\\archive\\dist.tar.gz" -destination dist.tar.gz -force' } } stage("Publish"){ steps { sshPublisher(publishers: [sshPublisherDesc(configName: '刚才设置的ssh的名称', sshRetry: [retries: 3, retryDelay: 5000], transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'powershell E:\\服务器B相关部署路径\\jenkins_deploy.ps1 -number $BUILD_NUMBER', execTimeout: , flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '服务器B相关部署路径', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'dist.tar.gz')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: true)]) } } } }
-
jenkins_deploy.ps1
#获取参数 param ( [string]$number ) #移动到当前目录 Set-Location E:\abc #设置时间变量 $date=(get-date).ToString('yyyy_MM_dd_HHmmss') #备份文件名 $backup_name = 'test_'+$date+'_'+$number+'.tar.gz' #将现有的打包 tar -zcvf $backup_name -C prod . #将打包后的移动到backup中 Move-Item -path $backup_name -destination backup\$backup_name -force Write-Output 'backup end' #清空prod文件夹 Remove-Item -path prod\* -recurse -force #将最新的解压到prod中 tar -zxvf dist.tar.gz -C prod Write-Output 'extra to prod' #删除传递过来的 Remove-item -path dist.tar.gz -force Write-Output 'finished'
-
-
powershell
各种方法的调用会更现代、简单一些,个人更推荐,需要大体了解下相关语法,参考PowerShell 在线教程或者PowerShell教程 。例如如果tar
没有加入环境变量,需要这样写才行& "xxxx\git\usr\bin\tar.exe" -zcvf xxxx
才行。 -
windows下
jenkins
和cmd
、powershell
的编码也是费劲,目前powershell
脚本文件不管是设置成ansi
,utf8-bom
,utf8
在jenkins中都是中文乱码,但是在本地运行ansi
,utf8-bom
格式不是乱码,但是utf8
格式是乱码,貌似windows powershell 5.1
如果用utf8
则必须用带bom
的,但最新的powershell 7
则改成不带bom
的utf8
。jenkins
也是,改了编码配置命令行展示正常了,但另一个地方又出现乱码,压根是冲突的,所以目前能写英文的都写英文的,就这样系统报错的话还是乱码,真是一堆的坑。 -
目前针对
powershell
还算正常的方式是:- 设置
ps1
脚本文件编码为utf8-bom
,可以用notepad++
等软件来转换下。 - 设置
powershell
软件本身的编码为utf8
,具体操作是打印$profile
可得到配置文件所在位置名称,在配置文件内(没有则自己新建个同名的)输入:$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
,保存后再次打开powershell
默认就是utf8
展示了。 - 设置
jenkins
的编码为utf8
,在其安装目录下的jenkins.xml
文件中在java
启动项中增加-Dfile.encoding=UTF-8
,重启即可。
- 设置
文章题目:windows下jenkins通过pipeline来部署和回滚maven、npm、小程序项目
文章出自:http://lswzjz.com/article/dschgpe.html