我正在为一个基于php的项目在jenkins中设置、自动构建和部署作业。我想对我的Jenkinsfile做一些反馈。特别是在并行化方面,(我认为)大量使用sh和站点配置的最佳实践(一堆包含的文件会更好吗?)
#!groovy
//TODO: SSH-steps? https://jenkins.io/blog/2019/02/06/ssh-steps-for-jenkins-pipeline/
//TODO: move some stuff to shared library for ease of use https://jenkins.io/doc/book/pipeline/shared-libraries/
node{
switch (env.BRANCH_NAME) {
case "Production":
echo "Production is not yet implemented"
//DEPLOY_DIR = ""
//SITE_TITLE = ""
//SITE_NAME = ""
//SITE_FQDN = ""
//DEFAULT_FROM_EMAIL = ""
//SESSION_NAME = ""
//MYSQL_HOSTNAME = ""
//MYSQL_DB_NAME = ""
//MYSQL_USERNAME = ""
//MYSQL_PASSWORD = ""
//SSH_SERVER_NAME = ""
//SSH_USERNAME = ""
break
case "Development":
case "development":
DEPLOY_DIR = "/var/www/somesite_dev"
SITE_TITLE = "blablabla"
SITE_NAME = "blablabla.dev.mydomain.dk"
SITE_FQDN = "blablabla.dev.mydomain.dk"
DEFAULT_FROM_EMAIL = "dev@mydaomain.dk"
SESSION_NAME = "TestSession"
MYSQL_HOSTNAME = "localhost"
MYSQL_DB_NAME = "somedb"
MYSQL_USERNAME = "uname"
MYSQL_PASSWORD = "p@sswørd" //TODO Move to Jenkins credential management
SSH_SERVER_NAME = "ssh.mydomain.dk"
SSH_USERNAME = "jenkins"
break
case "Test":
DEPLOY_DIR = "/var/www/somesite_test"
SITE_TITLE = "blablabla"
SITE_NAME = "blablabla.test.mydomain.dk"
SITE_FQDN = "blablabla.test.mydomain.dk"
DEFAULT_FROM_EMAIL = "test@mydaomain.dk"
SESSION_NAME = "DevSession"
MYSQL_HOSTNAME = "localhost"
MYSQL_DB_NAME = "somedb"
MYSQL_USERNAME = "uname"
MYSQL_PASSWORD = "p@sswørd" //TODO Move to Jenkins credential management
SSH_SERVER_NAME = "ssh.mydomain.dk"
SSH_USERNAME = "jenkins"
break
default:
echo "$BRANCH_NAME Does not yet have a configuration."
break
}
}
pipeline {
agent any
environment {
SOURCE_DIR="${WORKSPACE}/src"
BACKUP_FNAME="/tmp/BACKUP-${SITE_NAME}-${(new java.text.SimpleDateFormat("yyyy-MM-dd-HHmm")).format((new Date()))}.tar.gz"
}
triggers {
bitbucketPush()
pollSCM('') // empty cron expression string
}
stages {
stage ('Staging'){
environment {
TEMPLATE_FILE="globals.template.inc.php"
CONFIG_FILE="globals.inc.php"
}
steps {
echo "Cleanup build artifacts"
//remove build folder
sh 'rm -R -f ${WORKSPACE}/build'
echo "Prepare for build"
//re-create folders
sh 'mkdir ${WORKSPACE}/build ${WORKSPACE}/build/api ${WORKSPACE}/build/coverage ${WORKSPACE}/build/logs ${WORKSPACE}/build/pdepend ${WORKSPACE}/build/phpdox'
echo "Running composer"
sh "composer install -o -d ${SOURCE_DIR}"
echo "Building config file ${SOURCE_DIR}/${CONFIG_FILE}"
script {
def inptext = readFile file: "${SOURCE_DIR}/${TEMPLATE_FILE}"
//save deploydate
def deployDate = (new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm")).format((new Date()))
inptext = inptext.replaceAll(~/¤SITE_TITLE¤/, "${SITE_TITLE}")
inptext = inptext.replaceAll(~/¤SITE_NAME¤/, "${SITE_NAME}")
inptext = inptext.replaceAll(~/¤SITE_FQDN¤/, "${SITE_FQDN}")
inptext = inptext.replaceAll(~/¤DEFAULT_FROM_EMAIL¤/, "${DEFAULT_FROM_EMAIL}")
inptext = inptext.replaceAll(~/¤SESSION_NAME¤/, "${SESSION_NAME}")
inptext = inptext.replaceAll(~/¤MYSQL_HOSTNAME¤/, "${MYSQL_HOSTNAME}")
inptext = inptext.replaceAll(~/¤MYSQL_DB_NAME¤/, "${MYSQL_DB_NAME}")
inptext = inptext.replaceAll(~/¤MYSQL_USERNAME¤/, "${MYSQL_USERNAME}")
inptext = inptext.replaceAll(~/¤MYSQL_PASSWORD¤/, "${MYSQL_PASSWORD}")
inptext = inptext.replaceAll(~/¤DEPLOY_DATE¤/, "${deployDate}")
inptext = inptext.replaceAll(~/¤GIT_BRANCH¤/, "${env.GIT_BRANCH}")
inptext = inptext.replaceAll(~/¤GIT_COMMIT¤/, "${env.GIT_COMMIT}")
//inptext = inptext.replaceAll(~/¤GIT_TAG¤/, "${sh(returnStdout: true, script: "git -C . describe --tags").trim()}")
writeFile file: "${SOURCE_DIR}/${CONFIG_FILE}", text: inptext
}
}
}
stage ('Testing, Static Analysis & documenting'){
parallel {
stage ("Count LOC"){
steps {
// echo "Running Lint"
// sh "find . -path ./src/vendor -prune -o -type f -name '*.php' -print0 | xargs -0 -n1 -P4 php -l -n | (! grep -v \"No syntax errors detected\" )"
echo "Running phploc"
sh "./src/vendor/phploc/phploc/phploc --exclude=./src/vendor --no-interaction --quiet --log-csv=./build/logs/loc.csv src tests"
echo "Running sloc"
sh "sloccount --duplicates --wide --details . > ./build/logs/sloccount.sc 2>/dev/null"
}
}
stage ("Copy-Paste Detection"){
steps{
echo "Running copy-paste detection"
sh "./src/vendor/sebastian/phpcpd/phpcpd --fuzzy . --exclude src/vendor --log-pmd ./build/logs/phpcpd.xml || true"
}
}
stage ("Mess Detection"){
steps{
echo "Running mess detection on code"
sh "./src/vendor/phpmd/phpmd/src/bin/phpmd src xml phpmd_ruleset.xml --reportfile ./build/logs/phpmd_code.xml --exclude vendor,build --ignore-violations-on-exit --suffixes php"
//echo "Running mess detection on tests"
//sh "./src/vendor/phpmd/phpmd/src/bin/phpmd tests xml codesize,cleancode,unusedcode,naming --reportfile ./build/logs/phpmd_tests.xml --suffixes php"
}
}
stage ("Testing"){
steps{
echo "Running PHPUnit w/o code coverage"
sh "./src/vendor/phpunit/phpunit/phpunit --configuration phpunit-quick.xml"
}
}
//echo "Running PHP Codesniffer"
//sh "phpcs --report=checkstyle --report-file=./build/logs/checkstyle.xml --standard=PSR2 --extensions=php --ignore=autoload.php ./src ./tests"
//TODO: phpdox
// TODO: set up reporting
// https://wiki.jenkins.io/display/JENKINS/Plot+Plugin
// https://stackoverflow.com/a/48001251/1725871
}
}
stage ("Deploy") {
environment {
SSH_TUNNEL_PORT=3309
}
parallel {
stage ("Deploy code") {
agent any
steps {
echo "Deploying via SSH on ${SSH_SERVER_NAME}:${DEPLOY_DIR}"
//TODO: rename backup file
sh "ssh ${SSH_USERNAME}@${SSH_SERVER_NAME} tar -cvpzf ${BACKUP_FNAME} ${DEPLOY_DIR}/* "
sh "ssh ${SSH_USERNAME}@${SSH_SERVER_NAME} rm -R -f ${DEPLOY_DIR}/*"
sh "scp -rpC ${SOURCE_DIR}/* ${SSH_USERNAME}@${SSH_SERVER_NAME}:${DEPLOY_DIR}"
//TODO: delete backup on success
}
}
stage ("Deploy DB changes") {
agent any //liquibase
steps {
echo "Create SSH tunnel"
sh "ssh -M -S deploy-control-socket -fnNT -L ${SSH_TUNNEL_PORT}:localhost:3306 ${SSH_USERNAME}@${SSH_SERVER_NAME}"
echo "Check tunnel"
sh "ssh -S deploy-control-socket -O check ${SSH_USERNAME}@${SSH_SERVER_NAME}"
echo "Sync liquibase"
sh "liquibase --driver=com.mysql.cj.jdbc.Driver --changeLogFile=${WORKSPACE}/resources/database/db.changelog-1.1.xml --url=\"jdbc:mysql://127.0.0.1:${SSH_TUNNEL_PORT}/${MYSQL_DB_NAME}?autoReconnect=true&useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC\" --username=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD} update"
echo "Close SSH tunnel to ${SSH_SERVER_NAME}"
sh "ssh -S deploy-control-socket -O exit ${SSH_USERNAME}@${SSH_SERVER_NAME}"
}
}
}
}
}
post {
always {
//archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true
junit "build/logs/junit.xml"
sloccountPublish encoding: '', pattern: ''
// warnings-ng https://github.com/jenkinsci/warnings-ng-plugin/blob/master/doc/Documentation.md
recordIssues enabledForFailure: true, tool: cpd(pattern: 'build/logs/phpcpd.xml')
recordIssues enabledForFailure: true, tool: pmdParser(pattern: 'build/logs/phpmd_code.xml')
}
//https://jenkins.io/doc/pipeline/tour/post/
success {
echo 'Successful build. Well done'
}
unstable {
echo 'Unstable Build. Check test cases'
}
failure {
echo 'I failed :('
}
changed {
echo 'Things were different before...'
}
}
} 发布于 2019-09-22 19:26:01
我在备份和复制部分发现了一个固有的缺陷。即
sh "ssh ${SSH_USERNAME}@${SSH_SERVER_NAME} tar -cvpzf ${BACKUP_FNAME} ${DEPLOY_DIR}/*"
sh "ssh ${SSH_USERNAME}@${SSH_SERVER_NAME} rm -R -f ${DEPLOY_DIR}/*",它与本地mashine和https://stackoverflow.com/questions/22222838/shell-script-calling-ssh-how-to-interpret-wildcard-on-remote-server上的星号相同。
焦油的解决方案很简单:
sh "ssh ${SSH_USERNAME}@${SSH_SERVER_NAME} tar -cvpzf ${BACKUP_FNAME} ${DEPLOY_DIR}"rm的解决方案更加困难。我已经考虑过ssh步骤插件,但我希望在我尝试之前能更好地确定它是否能工作.
现在,我正在查看设置了rsync标志的--DELETE。
https://codereview.stackexchange.com/questions/227689
复制相似问题