Merge branch 'master' into developer
This commit is contained in:
10
deploy-tools/Dockerfile
Normal file
10
deploy-tools/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
FROM docker-new.cyweb.top/common/nginx:1.21.6
|
||||||
|
VOLUME /tmp
|
||||||
|
|
||||||
|
ARG profile
|
||||||
|
|
||||||
|
ENV LANG en_US.UTF-8
|
||||||
|
ADD ./nginx/${profile}.conf /etc/nginx/conf.d/default.conf
|
||||||
|
ADD ./dist/ /usr/share/nginx/html/
|
||||||
|
EXPOSE 80
|
||||||
|
EXPOSE 443
|
||||||
154
deploy-tools/Jenkinsfile
vendored
Normal file
154
deploy-tools/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
node("height_A") {
|
||||||
|
|
||||||
|
// name name path
|
||||||
|
|
||||||
|
def projectKey = "scj-v3-front-2026-1-6" //必须是每个项目唯一的key
|
||||||
|
|
||||||
|
def branch = "${env.BRANCH_NAME}" //当前分支变量
|
||||||
|
def toEmail = '493840844@qq.com,374362909@qq.com,278725160@qq.com,1012033624@qq.com' //需要接收邮件提醒的
|
||||||
|
def tag = sh(script: "echo `date +%s`", returnStdout: true).trim() //镜像tag
|
||||||
|
def registryHost = 'docker-new.cyweb.top' //har仓库
|
||||||
|
def harBorNamespace = 'project' //镜像存储目录
|
||||||
|
def artifactId = ''
|
||||||
|
def version = ''
|
||||||
|
def needSonarQube = false //是否开启代码质量检测
|
||||||
|
def isSuccess = true
|
||||||
|
def needNotice = true
|
||||||
|
def needIgnore = false
|
||||||
|
def realpathTemp = "";
|
||||||
|
def dockerImage = "";
|
||||||
|
def credentialsId = "";
|
||||||
|
def remoteHost = "";
|
||||||
|
def hostPort;
|
||||||
|
def namespace = "";
|
||||||
|
def profile = "";
|
||||||
|
|
||||||
|
try{
|
||||||
|
stage("初始化分支相关信息"){
|
||||||
|
switch(branch){
|
||||||
|
case 'developer' :
|
||||||
|
hostPort = 22
|
||||||
|
credentialsId = "scj-v3"
|
||||||
|
remoteHost = "192.168.42.127"
|
||||||
|
namespace = "scj-v3"
|
||||||
|
profile = "developer"
|
||||||
|
break;
|
||||||
|
case 'master':
|
||||||
|
hostPort = 22
|
||||||
|
credentialsId = "city-zhxy-deploy"
|
||||||
|
remoteHost = "192.168.41.228"
|
||||||
|
namespace = "scj-v3"
|
||||||
|
profile = "deploy"
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error('未配置分支!放弃执行')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
stage("获取最新代码"){
|
||||||
|
withFolderProperties{
|
||||||
|
sh 'printenv'
|
||||||
|
echo "当前分支${branch}"
|
||||||
|
git branch: "${branch}", credentialsId: 'git-ssh-auth', url: "${env.gitSource}"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stage("打包编译"){
|
||||||
|
nodejs(cacheLocationStrategy: workspace(), configId: 'bdb7fb3a-3aab-44ab-9d19-b55b4ae896ff', nodeJSInstallationName: '18.20')
|
||||||
|
{
|
||||||
|
sh 'npm config fix'
|
||||||
|
sh 'npm cache clean --force'
|
||||||
|
sh 'npm install --force'
|
||||||
|
// sh 'npm config fix'
|
||||||
|
sh 'npm run build'
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stage("docker 操作"){
|
||||||
|
if(!needIgnore)
|
||||||
|
{
|
||||||
|
withFolderProperties{
|
||||||
|
tool name: 'docker: 1.12.6', type: 'dockerTool'
|
||||||
|
withCredentials([usernamePassword(credentialsId: 'dockerharbor_new', passwordVariable: 'password', usernameVariable: 'username')]) {
|
||||||
|
echo "登录docker harbor"
|
||||||
|
sh "docker login ${registryHost} -u ${username} -p ${password} "
|
||||||
|
dockerImage = "${registryHost}/${harBorNamespace}/${projectKey}/${branch}/${projectKey}-${branch}:${tag} "
|
||||||
|
echo "镜像名称:"+dockerImage
|
||||||
|
sh "docker build --build-arg profile=${profile} -t ${dockerImage} -f ${env.WORKSPACE}/deploy-tools/Dockerfile . "
|
||||||
|
echo "提交镜像"
|
||||||
|
sh "docker push ${dockerImage} "
|
||||||
|
//删除本地镜像 防止磁盘漫
|
||||||
|
sh "docker rmi ${dockerImage} "
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
echo "略过"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
stage("更新服务"){
|
||||||
|
if(!needIgnore)
|
||||||
|
{
|
||||||
|
withFolderProperties{
|
||||||
|
echo "开始更新服务"
|
||||||
|
def remote = [:]
|
||||||
|
remote.name = "k8s-master-dev"
|
||||||
|
remote.host = "${remoteHost}"
|
||||||
|
remote.allowAnyHosts = true
|
||||||
|
|
||||||
|
withCredentials([sshUserPrivateKey(credentialsId: 'root-with-key-ubu-70', keyFileVariable: 'identity', passphraseVariable: '', usernameVariable: 'username')]) {
|
||||||
|
remote.user = "${username}"
|
||||||
|
remote.port = hostPort
|
||||||
|
remote.identityFile = identity
|
||||||
|
sshCommand remote: remote, command: "source ~/.bash_profile;kubectl set image deployment/front front=${dockerImage} --namespace=${namespace}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
echo "略过"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}catch(Exception e){
|
||||||
|
isSuccess = false
|
||||||
|
currentBuild.result = 'FAILURE'
|
||||||
|
|
||||||
|
throw e; //必须跑出异常 否则构建失败结果无法被jenkins捕获
|
||||||
|
|
||||||
|
}finally{
|
||||||
|
|
||||||
|
stage("发送邮件通知"){
|
||||||
|
if(needNotice)
|
||||||
|
{
|
||||||
|
// if(isSuccess)
|
||||||
|
// {
|
||||||
|
// emailext body: '${FILE,path="deploy-tools/email-notice-success.html"}', subject: '构建通知:${projectName} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS} 请勿回复', to: "$toEmail"
|
||||||
|
//
|
||||||
|
// }else{
|
||||||
|
// emailext body: '${FILE,path="deploy-tools/email-notice-false.html"}', subject: '构建通知:${projectName} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS} 请勿回复', to: "$toEmail"
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
138
deploy-tools/Jenkinsfile.back
Normal file
138
deploy-tools/Jenkinsfile.back
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
node("slave") {
|
||||||
|
|
||||||
|
def project = 'city-zhxy-front' //镜像名称
|
||||||
|
def gitSource = 'ssh://git@code.cyweb.top:30033/scj/zhxy-city/backend-front.git' //代码地址
|
||||||
|
def toEmail = '493840844@qq.com,374362909@qq.com' //需要接收邮件提醒的
|
||||||
|
// def namespace = "fund" //k8snamespaces
|
||||||
|
|
||||||
|
/******* 自定义变量,在jenkins必须对应设置 start *********/
|
||||||
|
def namespace = "${namespace}" //k8snamespaces
|
||||||
|
def branch = "${branch}" //当前分支变量
|
||||||
|
def profile = "${profile}" //dev
|
||||||
|
def remoteHost = "${remoteHost}" //部署服务器的ip
|
||||||
|
def remoteHostAuth = "${remoteHostAuth}" //部署服务器的凭证
|
||||||
|
/******* 自定义变量,在jenkins必须对应设置 end *********/
|
||||||
|
|
||||||
|
def tag = "jenkins-2021-${env.BUILD_NUMBER}" //镜像tag
|
||||||
|
|
||||||
|
def registryHost = 'docker.registry.cyweb.net:5000' //har仓库
|
||||||
|
def harBorNamespace = 'project' //镜像存储目录
|
||||||
|
|
||||||
|
def artifactId = ''
|
||||||
|
def version = ''
|
||||||
|
def needSonarQube = false //是否开启代码质量检测
|
||||||
|
def isSuccess = true
|
||||||
|
|
||||||
|
|
||||||
|
try{
|
||||||
|
stage("获取最新代码"){
|
||||||
|
sh 'printenv'
|
||||||
|
echo "当前分支${branch}"
|
||||||
|
git branch: "${branch}", credentialsId: 'git-ssh-auth', url: "${gitSource}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stage("打包编译"){
|
||||||
|
nodejs(cacheLocationStrategy: workspace(), configId: '066d1e6d-2a35-4832-96c1-78970fb7d78b', nodeJSInstallationName: 'node-10.15.1') {
|
||||||
|
sh 'npm install'
|
||||||
|
sh 'npm rebuild node-sass'
|
||||||
|
sh 'npm run build'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(needSonarQube){
|
||||||
|
stage("代码审查"){
|
||||||
|
def scannerHome = tool 'sonar-scanner'
|
||||||
|
withSonarQubeEnv('SonarQuber-Server') {
|
||||||
|
sh "${scannerHome}/bin/sonar-scanner " +
|
||||||
|
"-Dsonar.projectKey=${project}-${branch} " +
|
||||||
|
"-Dsonar.projectName=基金-开发分支 " +
|
||||||
|
"-Dsonar.sourceEncoding=UTF-8 " +
|
||||||
|
"-Dsonar.projectVersion=1.0 " +
|
||||||
|
"-Dsonar.java.binaries=./target/classes " +
|
||||||
|
"-Dsonar.sources=. "+
|
||||||
|
"-Dsonar.exclusions=**/test/**,**/target/**,**/main/resources/**,**/deploy-tools/** "+
|
||||||
|
"-Dsonar.java.source=1.8 "+
|
||||||
|
"-Dsonar.java.target=1.8"
|
||||||
|
|
||||||
|
// sh "${scannerHome}/bin/sonar-scanner -Dproject.settings=./deploy-tools/sonar-project.properties"
|
||||||
|
}
|
||||||
|
sleep(10)
|
||||||
|
timeout(time: 10, unit: 'MINUTES') {
|
||||||
|
def qg = waitForQualityGate()
|
||||||
|
if (qg.status != 'OK') {
|
||||||
|
echo "代码质量检测不通过"
|
||||||
|
error "Pipeline aborted due to quality gate failure: ${qg.status}"
|
||||||
|
}else{
|
||||||
|
echo "通过了代码质量检测"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stage("docker 操作"){
|
||||||
|
tool name: 'docker: 1.12.6', type: 'dockerTool'
|
||||||
|
withCredentials([usernamePassword(credentialsId: '193f70e2-0fc6-43dc-a1c6-c026d0fa3523', passwordVariable: 'password', usernameVariable: 'username')]) {
|
||||||
|
echo "登录docker harbor"
|
||||||
|
sh "docker login ${registryHost} -u ${username} -p ${password} "
|
||||||
|
// sh ' echo ${password} | docker login ${registryHost} -u Wang628625!@# --password-stdin '
|
||||||
|
echo "构建镜像"
|
||||||
|
sh "docker build --build-arg profile=${profile} -t ${registryHost}/${harBorNamespace}/${project}/${project}-${profile}:${tag} -f deploy-tools/Dockerfile . "
|
||||||
|
echo "提交镜像"
|
||||||
|
sh "docker push ${registryHost}/${harBorNamespace}/${project}/${project}-${profile}:${tag} "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
stage("更新服务"){
|
||||||
|
echo "开始更新服务"
|
||||||
|
def remote = [:]
|
||||||
|
remote.name = "k8s-master-dev"
|
||||||
|
remote.host = "${remoteHost}"
|
||||||
|
remote.allowAnyHosts = true
|
||||||
|
|
||||||
|
|
||||||
|
withCredentials([usernamePassword(credentialsId: "${remoteHostAuth}", passwordVariable: 'passowrd', usernameVariable: 'username')]) {
|
||||||
|
remote.user = "${username}"
|
||||||
|
remote.password = "${passowrd}"
|
||||||
|
sshCommand remote: remote, command: 'source ~/.bash_profile'
|
||||||
|
sshCommand remote: remote, command: "kubectl set image deployment/front front=${registryHost}/${harBorNamespace}/${project}/${project}-${profile}:${tag} --namespace=${namespace}"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}catch(Exception e){
|
||||||
|
isSuccess = false
|
||||||
|
currentBuild.result = 'FAILURE'
|
||||||
|
|
||||||
|
throw e; //必须跑出异常 否则构建失败结果无法被jenkins捕获
|
||||||
|
|
||||||
|
}finally{
|
||||||
|
|
||||||
|
stage("发送邮件通知"){
|
||||||
|
if(isSuccess)
|
||||||
|
{
|
||||||
|
emailext body: '${FILE,path="deploy-tools/email-notice-success.html"}', subject: '构建通知:{$PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS} 请勿回复', to: "$toEmail"
|
||||||
|
|
||||||
|
}else{
|
||||||
|
emailext body: '${FILE,path="deploy-tools/email-notice-false.html"}', subject: '构建通知:{$PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS} 请勿回复', to: "$toEmail"
|
||||||
|
|
||||||
|
}
|
||||||
|
// echo "clear workspace......"
|
||||||
|
// deleteDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
77
deploy-tools/email-notice-false.html
Normal file
77
deploy-tools/email-notice-false.html
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
|
||||||
|
offset="0">
|
||||||
|
<table width="95%" cellpadding="0" cellspacing="0"
|
||||||
|
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
||||||
|
<tr>
|
||||||
|
<td>(本邮件是程序自动下发的,请勿回复!)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><h2>
|
||||||
|
<font color="#FF0000">构建结果 - ${BUILD_STATUS}</font>
|
||||||
|
</h2></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><br />
|
||||||
|
<b><font color="#0B610B">构建信息</font></b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li>项目名称 : ${PROJECT_NAME}</li>
|
||||||
|
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
|
||||||
|
<li>触发原因: ${CAUSE}</li>
|
||||||
|
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
|
||||||
|
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
|
||||||
|
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}</a></li>
|
||||||
|
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b><font color="#0B610B">Changes Since Last
|
||||||
|
Successful Build:</font></b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
|
||||||
|
</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat=" %p"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Failed Test Results</b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre
|
||||||
|
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
|
||||||
|
<br /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b><font color="#0B610B">构建日志 (最后 100行):</font></b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Test Logs (if test has ran):
|
||||||
|
<a href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip">${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><textarea cols="80" rows="30" readonly="readonly"
|
||||||
|
style="font-family: Courier New">${BUILD_LOG}</textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
77
deploy-tools/email-notice-success.html
Normal file
77
deploy-tools/email-notice-success.html
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
|
||||||
|
offset="0">
|
||||||
|
<table width="95%" cellpadding="0" cellspacing="0"
|
||||||
|
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
||||||
|
<tr>
|
||||||
|
<td>(本邮件是程序自动下发的,请勿回复!)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><h2>
|
||||||
|
<font color="#228B22">构建结果 - ${BUILD_STATUS}</font>
|
||||||
|
</h2></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><br />
|
||||||
|
<b><font color="#0B610B">构建信息</font></b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li>项目名称 : ${PROJECT_NAME}</li>
|
||||||
|
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
|
||||||
|
<li>触发原因: ${CAUSE}</li>
|
||||||
|
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
|
||||||
|
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
|
||||||
|
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}</a></li>
|
||||||
|
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b><font color="#0B610B">Changes Since Last
|
||||||
|
Successful Build:</font></b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
|
||||||
|
</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat=" %p"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Failed Test Results</b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><pre
|
||||||
|
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
|
||||||
|
<br /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b><font color="#0B610B">构建日志 (最后 100行):</font></b>
|
||||||
|
<hr size="2" width="100%" align="center" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Test Logs (if test has ran):
|
||||||
|
<a href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip">${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><textarea cols="80" rows="30" readonly="readonly"
|
||||||
|
style="font-family: Courier New">${BUILD_LOG}</textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user