* Add ci pipeline code

This commit is contained in:
qishiyao
2023-10-30 16:54:43 +08:00
parent c94677b399
commit 3c9c64f96a
15 changed files with 1981 additions and 8 deletions
+27 -8
View File
@@ -1,6 +1,6 @@
VERSION = $(shell head -n 1 VERSION)
XUANVERSION = $(shell head -n 1 extension/xuanxuan/XUANVERSION)
XVERSION = $(shell head -n 1 extension/xuanxuan/XVERSION)
XUANVERSION = $(shell jq -r .pkg.xuanxuan.gitVersion < ci.json)
XVERSION = $(shell jq -r .pkg.xuanxuan.version < ci.json)
XHPROF_VERSION = 2.3.9
XUANPATH := $(XUANXUAN_SRC_PATH)
@@ -8,6 +8,9 @@ BUILD_PATH := $(if $(ZENTAO_BUILD_PATH),$(ZENTAO_BUILD_PATH),$(shell pwd))
RELEASE_PATH := $(if $(ZENTAO_RELEASE_PATH),$(ZENTAO_RELEASE_PATH),$(shell pwd))
XUAN_WEB_PATH := $(ZENTAO_BUILD_PATH)/web
DOWNGRADE_ENABLED := $(or $(DOWNGRADE_ENABLED),$(shell jq -r .downgrade.enabled < ci.json))
DOWNGRADE_VERSIONS := $(or $(DOWNGRADE_VERSIONS),$(shell jq -r .downgrade.versions < ci.json))
all:
make clean
make ci
@@ -97,6 +100,8 @@ zentaoxx:
cp -r $(XUAN_WEB_PATH) zentaoxx/www/data/xuanxuan/
mv zentaoxx/db/ zentaoxx/db_bak
mkdir zentaoxx/db/
sed -i "s/datetime NOT NULL DEFAULT '0000-00-00 00:00:00'/datetime NULL/" zentaoxx/db_bak/*.sql
sed -i "/`xxb_user` ADD `clientStatus`/d; /`xxb_user` ADD `clientLang`/d; /`xxb_file` CHANGE `pathname`/d" zentaoxx/db_bak/xuanxuan.sql
cp zentaoxx/db_bak/upgradexuanxuan*.sql zentaoxx/db_bak/xuanxuan.sql zentaoxx/db/
rm -rf zentaoxx/db_bak/
sed -i "s/\$$accountAdmin = \$$this->dao->select('account, admin')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();/\$$accountAdmin = \$$this->dao->select('account')->from(TABLE_USER)->where('id')->eq(\$$userID)->fetch();\n\$$sysAdmins = \$$this->dao->select('admins')->from(TABLE_COMPANY)->where('id')->eq(\$$this->app->company->id)->fetch('admins');\n\$$sysAdminArray = explode(',', \$$sysAdmins);\n\$$accountAdmin->admin = in_array(\$$accountAdmin->account, \$$sysAdminArray) ? 'super' : '';\n/" zentaoxx/extension/xuan/im/model/chat.php
@@ -131,6 +136,7 @@ zentaoxx:
sed -i '/xxb_entry/d' zentaoxx/db/*.sql
sed -i '/deviceToken/d' zentaoxx/db/*.sql
sed -i '/deviceType/d' zentaoxx/db/*.sql
sed -i 's/xxb_/zt_/g' zentaoxx/db/*.sql
sed -i "/fetch('push', 'pushMessage');/d" zentaoxx/extension/xuan/im/control.php
#sed -i "s/marked\.html\.php';?>/marked\.html\.php';?>\n<div id='mainMenu' class='clearfix'><div class='btn-toolbar pull-left'><?php common::printAdminSubMenu('xuanxuan');?><\/div><\/div>/g" zentaoxx/extension/xuan/client/view/checkupgrade.html.php
sed -i '/var serverVersions/d' zentaoxx/extension/xuan/client/js/checkupgrade.js
@@ -146,14 +152,20 @@ zentaoxx:
sed -i 's/commonModel::getLicensePropertyValue/extCommonModel::getLicensePropertyValue/g' zentaoxx/extension/xuan/im/control.php
sed -i 's/commonModel::getLicensePropertyValue/extCommonModel::getLicensePropertyValue/g' zentaoxx/extension/xuan/im/model/conference.php
sed -i 's/xxb_/zt_/g' zentaoxx/db/*.sql
sed -i 's/commonModel::isLicensedMethod([^\)]*)/false/g' zentaoxx/extension/xuan/conference/model.php
sed -i "s#\$this->app->getModuleRoot() . 'im/apischeme.json'#\$this->app->getExtensionRoot() . 'xuan/im/apischeme.json'#g" zentaoxx/extension/xuan/im/model.php
sed -i "s/'..\/..\/common\/view\/header.html.php'/\$$app->getModuleRoot() . 'common\/view\/header.html.php'/g" zentaoxx/extension/xuan/conference/view/admin.html.php
sed -i "s/'..\/..\/common\/view\/footer.html.php'/\$$app->getModuleRoot() . 'common\/view\/footer.html.php'/g" zentaoxx/extension/xuan/conference/view/admin.html.php
sed -i "s/\$$this->im->userGetChangedPassword()/array()/" zentaoxx/extension/xuan/im/control.php
sed -i "s/->app->getModuleExtPath('', /->app->getModuleExtPath(/g" zentaoxx/extension/xuan/im/model/bot.php
sed -i "s/\$$this->getModuleExtPath('', /\$$this->getModuleExtPath(/g" zentaoxx/framework/xuanxuan.class.php
sed -i "s/, \$$version)\$$/, \$$version = '')/g" zentaoxx/extension/xuan/im/model.php
sed -i "s/, \$$version)\$$/, \$$version = '')/g" zentaoxx/extension/xuan/im/model/conference.php
sed -i "/.*->getAllDepts();/d" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
sed -i "s/lang->user->status/lang->user->clientStatus/" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
sed -i "s/.*->getRoleList();/\$$depts = \$$this->im->loadModel('dept')->getDeptPairs();\n\$$deptList = array_map(function(\$$k, \$$v) {return (object)array('id' => \$$k, 'name' => \$$v);}, array_keys(\$$depts), \$$depts);\n\$$roleList = \$$this->im->lang->user->roleList;/" zentaoxx/extension/xuan/im/ext/bot/default.bot.php
echo "ALTER TABLE \`zt_user\` ADD \`pinyin\` varchar(255) NOT NULL DEFAULT '' AFTER \`realname\`;" >> zentaoxx/db/xuanxuan.sql
find zentaoxx/extension/xuan/ -name '*.php' -exec sed -i -r 's|->ne(["'\'']0000-00-00 00:00:00["'\''])|->notZeroDatetime()|g; s|["'\'']\)->eq\(["'\'']0000-00-00( 00:00:00)?| is null|g; s|([=!]=) ?["'\'']0000-00-00( 00:00:00)?["'\'']|\1 null|g; s|([^!=]=) ?["'\'']0000-00-00( 00:00:00)?["'\'']|\1 null|g; s|(["'\''])(,.*)\)->eq\(["'\'']0000-00-00( 00:00:00)?["'\'']| is null\1\2|g; s|["'\'']0000-00-00 00:00:00["'\'']|null|g' {} +
mkdir zentaoxx/misc; cp misc/cn2tw.php zentaoxx/misc; cd zentaoxx/misc; php cn2tw.php
cp misc/en2other.php zentaoxx/misc; cd zentaoxx/misc; php en2other.php ../
rm -rf zentaoxx/misc
@@ -253,8 +265,9 @@ enrpm:
rpmbuild -ba ~/rpmbuild/SPECS/zentaopms.spec
cp ~/rpmbuild/RPMS/noarch/zentaoalm-${VERSION}-1.noarch.rpm ./
rm -rf ~/rpmbuild
cleanAssets:
find zentaopms/ -type f \( -name "*.js.map" -o -name "*.gz" \) -delete
ciCommon:
make clean
make common
ifneq ($(XUANPATH), )
@@ -264,14 +277,20 @@ ciCommon:
endif
make package
make cleanAssets
zip -rq -9 ZenTaoPMS.$(VERSION).zip zentaopms
# en
cd zentaopms/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
cd zentaopms/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
cd zentaopms/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
mv zentaopms zentaoalm
cp -a zentaopms zentaoalm
cd zentaoalm/; grep -rl 'zentao.net'|xargs sed -i 's/zentao.net/zentao.pm/g';
cd zentaoalm/; grep -rl 'http://www.zentao.pm'|xargs sed -i 's/http:\/\/www.zentao.pm/https:\/\/www.zentao.pm/g';
cd zentaoalm/config/; echo >> config.php; echo '$$config->isINT = true;' >> config.php
zip -rq -9 ZenTaoALM.$(VERSION).int.zip zentaoalm
rm -fr zentaoalm
# downgrade
@test "$(DOWNGRADE_ENABLED)" != "true" && echo "skip downgrade" || ./misc/downgrade.sh -p "$(DOWNGRADE_VERSIONS)" -i -r zentaopms -o "$(RELEASE_PATH)" framework/ lib/ module/*
rm -fr zentaopms zentaoalm
# move pms zip to build and release path.
rm -f $(BUILD_PATH)/ZenTao*.zip $(RELEASE_PATH)/ZenTaoPMS.$(VERSION).zip $(RELEASE_PATH)/ZenTaoALM.$(VERSION).int.zip
cp ZenTaoPMS.$(VERSION).zip $(BUILD_PATH)
+49
View File
@@ -0,0 +1,49 @@
{
"pkg": {
"xuanxuan": {
"gitVersion": "f3895b8a80f269c81813c177ede6e81a86219cd0",
"version": "7.2.1"
},
"zentaoext": {
"gitVersion": "master",
"gitRepo": "https://git.zcorp.cc/easycorp/zentaoext.git"
},
"zdoo": {
"gitVersion": "master"
},
"zdooext": {
"gitVersion": "master"
}
},
"image": {
"public": {
"namespace": {
"release": "app",
"snapshot": "test"
}
},
"internal": {
"namespace": {
"release": "app",
"snapshot": "test"
}
}
},
"downgrade": {
"enabled": true,
"versions": "7.2,7.1,7.0,5.4"
},
"upload": {
"bucket": "download",
"nexus": {
"release": "easycorp",
"snapshot": "easycorp-snapshot"
}
},
"notice": {
"users": "qishiyao",
"usersX": "qishiyao,hufangzhou",
"groupsX": "84be4c6e-02e3-4fdc-b081-318c0c1eca02,31a0008b-6e3e-4b7f-9b7b-396a46b1f8f4",
"groups2X": "84be4c6e-02e3-4fdc-b081-318c0c1eca02,31a0008b-6e3e-4b7f-9b7b-396a46b1f8f4,6f5bb3f5-f4e3-4f67-963e-0cc9d59ad3c7"
}
}
+606
View File
@@ -0,0 +1,606 @@
library 'z-common@feat-231024'
library 'z-zentaopms@feat-231019'
pipeline {
agent {
kubernetes {
inheritFrom "xuanim"
yamlFile 'misc/ci/normal.yaml'
}
}
options {
skipDefaultCheckout()
parallelsAlwaysFailFast()
overrideIndexTriggers(false)
quietPeriod 900
}
parameters {
choice choices: ['auto', 'snapshot', 'release'], description: '构建包类型(快照或发版)', name: 'build_kind'
booleanParam defaultValue: true, description: '制作源码包', name: 'publish_zip'
booleanParam defaultValue: true, description: '制作镜像', name: 'publish_image'
booleanParam defaultValue: true, description: '制作一键安装包', name: 'publish_zbox'
// booleanParam defaultValue: true, description: '开启代码降级', name: 'DOWNGRADE_ENABLED'
string description: '指定一个构建Id用于回放,适用于tag类型的job', name: 'REPLAY_ID', trim: true
}
environment {
TZ="Asia/Shanghai"
ZENTAO_RELEASE_PATH = "${WORKSPACE}/release"
XUANXUAN_SRC_PATH = "${WORKSPACE}/xuansrc"
SRC_ZDOO_PATH = "${WORKSPACE}/zdoo"
SRC_ZDOOEXT_PATH = "${WORKSPACE}/zdooext"
SRC_ZENTAOEXT_PATH = "${WORKSPACE}/zentaoext"
MIDDLE_IMAGE_REPO = "hub.qc.oop.cc/zentao-package-ext"
MIDDLE_IMAGE_TAG = """${sh(
returnStdout: true,
script: 'date +%Y%m%d%H%M-${BUILD_ID}'
).trim()}"""
MIRROR = "true"
// 默认从job参数里读取,打开后覆盖
PUBLISH_ZIP = "${params.publish_zip}"
PUBLISH_IMAGE = "${params.publish_image}"
PUBLISH_ZBOX = "${params.publish_zbox}"
// set to blank for auto-detect from ci.json
DOWNGRADE_ENABLED = ""
DOWNGRADE_VERSIONS = ""
}
stages {
stage("Basic Build") {
when {
anyOf {
buildingTag()
not {
triggeredBy 'BranchEventCause'
}
}
}
agent {
kubernetes {
inheritFrom "zentao-package build-docker xuanim"
yamlFile 'misc/ci/basic-build.yaml'
}
}
stages {
stage("Pull") {
steps {
checkout scm
script {
def triggeredBy = currentBuild.getBuildCauses()
println "Build triggered by: ${triggeredBy}"
job.DetectTrigger()
env.XUANVERSION = sh(returnStdout: true,script: 'jq -r .pkg.xuanxuan.gitVersion < ci.json').trim()
env.ZENTAOEXT_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zentaoext.gitVersion < ci.json').trim()
env.ZENTAOEXT_GIT_REPO = sh(returnStdout: true,script: 'jq -r .pkg.zentaoext.gitRepo < ci.json').trim()
env.ZDOO_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zdoo.gitVersion < ci.json').trim()
env.ZDOOEXT_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zdooext.gitVersion < ci.json').trim()
if (params.build_kind=='auto') {
env.BUILD_KIND = "snapshot"
if (env.TAG_NAME) {
def testStr = env.TAG_NAME
def count = testStr.count(/_/)
if (count==1) {
env.BUILD_KIND = "release"
}
}
} else {
env.BUILD_KIND = params.build_kind
}
}
replayCheckout([
[name: "xuansrc", subDir: true, url: "https://git.zcorp.cc/easycorp/xuanxuan.git", credentialsId: "git-zcorp-cc-jenkins-bot-http", branch: "${env.XUANVERSION}", depth: 0],
[name: "zdoo", subDir: true, url: "https://git.zcorp.cc/easycorp/zdoo.git", credentialsId: "git-zcorp-cc-jenkins-bot-http", branch: "${env.ZDOO_VERSION}", depth: 2],
[name: "zdooext", subDir: true, url: "https://git.zcorp.cc/easycorp/zdooext.git", credentialsId: "git-zcorp-cc-jenkins-bot-http", branch: "${env.ZDOOEXT_VERSION}", depth: 2],
[name: "zentaoext", subDir: true, url: "${env.ZENTAOEXT_GIT_REPO}", credentialsId: "git-zcorp-cc-jenkins-bot-http", branch: "${env.ZENTAOEXT_VERSION}", depth: 2]
])
}
}
stage("Setup Global Env") {
steps {
sh 'env'
script {
// GIT_URL GIT_COMMIT isn't export to env by jenkins. fetch by self
env.GIT_URL = sh(returnStdout: true, script: 'git config --get remote.origin.url').trim()
env.GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
job.BuildHeader()
// env.GIT_TAGGER_NAME = sh(returnStdout: true, script: 'git for-each-ref --format="%(taggername)" refs/tags/$(git tag --points-at HEAD)').trim()
env.CI_PUBLIC_IMAGE_NAMESPACE = sh(returnStdout: true,script: 'jq -r .image.public.namespace.' + env.BUILD_KIND + ' < ci.json').trim()
env.CI_INTERNAL_IMAGE_NAMESPACE = sh(returnStdout: true,script: 'jq -r .image.internal.namespace.' + env.BUILD_KIND + ' < ci.json').trim()
def ximUsers = sh(returnStdout: true,script: 'jq -r .notice.users < ci.json').trim()
env.XIM_USERS = ximUsers + ',' + env.GIT_TAGGER_NAME
if (env.BUILD_KIND=='release') {
env.XIM_GROUPS = sh(returnStdout: true,script: 'jq -r .notice.groups2 < ci.json').trim()
} else {
env.XIM_GROUPS = sh(returnStdout: true,script: 'jq -r .notice.groups < ci.json').trim()
}
env.PMS_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/VERSION').trim()
env.BIZ_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/BIZVERSION').trim()
env.MAX_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/MAXVERSION').trim()
env.IPD_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/IPDVERSION').trim()
env.DOCKER_CREDENTIALS_ID = 'hub-qucheng-push'
env.CI_DOWNGRADE_ENABLED = sh(returnStdout: true, script: 'test -n "${DOWNGRADE_ENABLED}" && echo ${DOWNGRADE_ENABLED} || (jq -r .downgrade.enabled < ci.json)').trim()
env.QINIU_BUCKET = sh(returnStdout: true, script: 'jq -r .upload.bucket < ci.json').trim()
if (env.BUILD_KIND=='release') {
env.ARTIFACT_SUBGROUP='release'
} else {
currentDate = sh(returnStdout: true, script: 'date +%Y%m%d').trim()
env.ARTIFACT_SUBGROUP = currentDate + '.' + env.GIT_COMMIT[0..6]
}
env.ARTIFACT_REPOSITORY = sh(returnStdout: true,script: 'jq -r .upload.nexus.' + env.BUILD_KIND + ' < ci.json').trim()
env.ARTIFACT_HOST = "nexus.qc.oop.cc"
env.ARTIFACT_PROTOCOL = "https"
env.ARTIFACT_CRED_ID = "nexus-jenkins"
def mdPath = "start.md"
job.BuildChangeSetMd(mdPath)
job.unStashMsgHeader()
ximNotify(title: "开始构建禅道", contentFile: mdPath, contentHeaderFile: job.headerFileName())
}
}
}
stage("Build") {
when {
environment name:'PUBLISH_ZIP', value:'true'
}
stages {
stage("make ciCommon") {
steps {
withCredentials([gitUsernamePassword(credentialsId: 'git-zcorp-cc-jenkins-bot-http',gitToolName: 'git-tool')]) {
container('package') {
sh 'mkdir ${ZENTAO_RELEASE_PATH} && chown 1000:1000 ${ZENTAO_RELEASE_PATH}'
sh 'git config --global pull.ff only'
sh 'cp -av ${ZENTAO_BUILD_PATH}/adminer www/'
sh 'pwd && ls -l && make ciCommon'
sh 'ls -l ${ZENTAO_RELEASE_PATH}'
}
}
}
}
stage("zentaoext") {
steps {
container('package') {
sh 'cd $SRC_ZENTAOEXT_PATH && make'
sh 'cp ${ZENTAO_BUILD_PATH}/zentao*.zip ./'
sh 'cp ${ZENTAO_BUILD_PATH}/docker/Dockerfile.release.ext ./Dockerfile.release.ext'
}
container('docker') {
sh 'docker build --pull -t ${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG} -f Dockerfile.release.ext ${ZENTAO_RELEASE_PATH}'
sh 'docker push ${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}'
}
script {
buildPkg.uploadSource()
}
}
}
}
} // End Build
}
}
stage("Publish") {
environment {
OUTPUT_PKG_PATH = "${ZENTAO_RELEASE_PATH}/output"
}
stages {
stage("Merge and Upload") {
when {
environment name:'PUBLISH_ZIP', value:'true'
}
matrix {
agent {
kubernetes {
containerTemplate {
name "package"
image "${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}"
command "sleep"
args "99d"
}
yamlFile 'misc/ci/publish-zip.yaml'
}
}
options {
skipDefaultCheckout()
}
axes {
axis {
name "ZLANG"
values "cn", "en"
}
axis {
name "PHPVERSION"
values "php5.4_5.6", "php7.0", "php7.1", "php7.2_7.4", "k8s.php7.2_7.4", "php8.1", "k8s.php8.1"
}
}
excludes {
exclude {
axis {
name 'ZLANG'
values 'en'
}
axis {
name "PHPVERSION"
values "k8s.php7.2_7.4", "k8s.php8.1"
}
}
}
stages {
stage("ZIP") {
environment {
ARTIFACT_NAME = """${sh(
returnStdout: true,
script: 'test ${ZLANG} = cn && echo -n ZenTaoPMS || echo -n ZenTaoALM'
).trim()}"""
INT_FLAG = """${sh(
returnStdout: true,
script: 'test ${ZLANG} = cn && echo -n "int." || echo -n ""'
).trim()}"""
}
stages {
stage("package zip") {
steps{
echo "${env.ZLANG} <=> ${env.PHPVERSION}"
container('package') {
sh 'mkdir $ZENTAO_RELEASE_PATH'
sh '${ZENTAO_BUILD_PATH}/package.sh zip'
sh 'mkdir $OUTPUT_PKG_PATH'
}
}
}
stage("upload zip") {
steps {
sh 'mkdir ${OUTPUT_PKG_PATH}/${PMS_VERSION}'
sh 'cp ${ZENTAO_RELEASE_PATH}/base.zip ${OUTPUT_PKG_PATH}/${PMS_VERSION}/${ARTIFACT_NAME}-${PMS_VERSION}-${PHPVERSION}.zip'
script {
buildPkg.uploadPMS(env.PHPVERSION)
// copy php7.2 as php8.0
if (env.PHPVERSION=="php7.2_7.4") {
buildPkg.uploadPMS('php8.0')
sh 'cp ${ZENTAO_RELEASE_PATH}/base.zip ${OUTPUT_PKG_PATH}/${PMS_VERSION}/${ARTIFACT_NAME}-${PMS_VERSION}-php8.0.zip'
}
buildPkg.uploadExt()
}
}
} // End upload zip
stage("syspack") {
when {
environment name: 'BUILD_KIND', value: 'release'
}
steps{
script {
buildPkg.buildRpmAndDeb()
}
}
}
stage("Upload Qiniu") {
when {
environment name: 'BUILD_KIND', value: 'release'
}
environment {
OBJECT_KEY_PREFIX = "zentao/"
QINIU_ACCESS_KEY = credentials('qiniu-upload-ak')
QINIU_SECRET_KEY = credentials('qiniu-upload-sk')
}
steps {
sh 'ls -l ${OUTPUT_PKG_PATH}'
container('jnlp') {
sh 'qshell account $QINIU_ACCESS_KEY $QINIU_SECRET_KEY uploader'
sh 'qshell qupload2 --bucket $QINIU_BUCKET --overwrite --src-dir $OUTPUT_PKG_PATH --key-prefix $OBJECT_KEY_PREFIX'
}
}
}
} // end stages
} // end stage frame
} // End matrix stages
} // End matrix
} // End Merge and Upload Max
stage("Notice ZIP") {
when { environment name:'PUBLISH_ZIP', value:'true' }
steps {
checkout scmGit(branches: [[name: "master"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/devops/zentao-package.git']]
)
container('xuanimbot') {
sh './gen_build_report.sh > success.md'
}
script {
job.unStashMsgHeader()
ximNotify(title: "禅道源码包构建成功", contentFile: "success.md", contentHeaderFile: job.headerFileName())
}
}
}
stage("Zbox") {
when { environment name:'PUBLISH_ZBOX', value:'true' }
environment {
// printf "$PKG_URL_FORMATTER" pmsPack ZenTaoPMS 18.5 ZenTaoPMS-18.5-php8.1.zip
PKG_URL_FORMATTER = """${sh(
returnStdout: true,
script: "echo ${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/repository/${ARTIFACT_REPOSITORY}/zentao/%s/`echo ${ARTIFACT_SUBGROUP} | tr . /`/%s/%s/%s"
).trim()}"""
OBJECT_KEY_PREFIX = "zentao/"
QINIU_ACCESS_KEY = credentials('qiniu-upload-ak')
QINIU_SECRET_KEY = credentials('qiniu-upload-sk')
}
stages {
stage("Package") {
parallel {
stage("Zbox win") {
agent {
kubernetes {
yamlFile 'misc/ci/publish-zbox.yaml'
}
}
stages() {
stage("Prepare") {
steps {
checkout scmGit(branches: [[name: "main"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/devops/zbox-builder.git']]
)
}
}
stage("Build") {
steps {
script {
buildZboxWin.doBuild()
buildZboxWin.uploadInternal()
}
}
}
stage("Upload Qiniu") {
when {
environment name: 'BUILD_KIND', value: 'release'
}
steps {
container('docker') {
sh 'mkdir -pv ./release/upload && cd ./release/upload && mkdir $PMS_VERSION $BIZ_VERSION $MAX_VERSION $IPD_VERSION'
sh "mv `find release/zh-cn/$PMS_VERSION release/en/$PMS_VERSION -type f -name 'ZenTao*.exe'` release/upload/$PMS_VERSION"
sh "mv `find release/zh-cn/$BIZ_VERSION release/en/$BIZ_VERSION -type f -name 'ZenTao*.exe'` release/upload/$BIZ_VERSION"
sh "mv `find release/zh-cn/$MAX_VERSION release/en/$MAX_VERSION -type f -name 'ZenTao*.exe'` release/upload/$MAX_VERSION"
sh "mv `find release/zh-cn/$IPD_VERSION release/en/$IPD_VERSION -type f -name 'ZenTao*.exe'` release/upload/$IPD_VERSION"
}
container('jnlp') {
sh 'qshell account $QINIU_ACCESS_KEY $QINIU_SECRET_KEY uploader'
sh 'qshell qupload2 --bucket $QINIU_BUCKET --overwrite --src-dir ./release/upload --key-prefix $OBJECT_KEY_PREFIX'
}
}
} // End Upload Qiniu
}
} // End Zbox win
stage("Zbox linux") {
agent {
kubernetes {
yamlFile 'misc/ci/publish-zbox.yaml'
}
}
stages() {
stage("Prepare") {
steps {
checkout scmGit(branches: [[name: "main"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/devops/zbox-builder.git']]
)
}
}
stage("Build") {
steps {
script {
buildZboxLinux.doBuild()
buildZboxLinux.uploadInternal()
}
}
}
stage("Upload Qiniu") {
when {
environment name: 'BUILD_KIND', value: 'release'
}
steps {
container('docker') {
sh 'mkdir -pv ./release/upload && cd ./release/upload && mkdir $PMS_VERSION $BIZ_VERSION $MAX_VERSION $IPD_VERSION'
sh "mv `find release/zh-cn/$PMS_VERSION release/en/$PMS_VERSION -type f -name 'ZenTao*'` release/upload/$PMS_VERSION"
sh "mv `find release/zh-cn/$BIZ_VERSION release/en/$BIZ_VERSION -type f -name 'ZenTao*'` release/upload/$BIZ_VERSION"
sh "mv `find release/zh-cn/$MAX_VERSION release/en/$MAX_VERSION -type f -name 'ZenTao*'` release/upload/$MAX_VERSION"
sh "mv `find release/zh-cn/$IPD_VERSION release/en/$IPD_VERSION -type f -name 'ZenTao*'` release/upload/$IPD_VERSION"
}
container('jnlp') {
sh 'qshell account $QINIU_ACCESS_KEY $QINIU_SECRET_KEY uploader'
sh 'qshell qupload2 --bucket $QINIU_BUCKET --overwrite --src-dir ./release/upload --key-prefix $OBJECT_KEY_PREFIX'
}
}
} // End Upload Qiniu
}
} // End Zbox linux
} // End parallel
}
stage("Notice zbox") {
steps {
checkout scmGit(branches: [[name: "main"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/devops/zbox-builder.git']]
)
sh 'script/lib/gen_report.sh > zbox-success.md'
script {
job.unStashMsgHeader()
ximNotify(title: "禅道一键安装包构建成功", contentFile: "zbox-success.md", contentHeaderFile: job.headerFileName())
}
}
}
}
} // End Zbox
stage("Docker Image") {
when {
environment name:'PUBLISH_IMAGE', value:'true'
}
agent {
kubernetes {
inheritFrom "dind xuanim"
yamlFile 'misc/ci/publish-image.yaml'
}
}
environment {
REGISTRY_HOST="hub.zentao.net"
CI_BUILD_PUBLIC_IMAGE="true"
PKG_URL_FORMATTER = """${sh(
returnStdout: true,
script: "echo ${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/repository/${ARTIFACT_REPOSITORY}/zentao/%s/`echo ${ARTIFACT_SUBGROUP} | tr . /`/%s/%s/%s"
).trim()}"""
}
steps {
checkout scmGit(branches: [[name: "master"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/app/zentao.git']]
)
script {
dockerBuildx(host=env.REGISTRY_HOST, credentialsId=env.DOCKER_CREDENTIALS_ID) {
stage("prepare") {
sh "apk --no-cache add make bash jq git tzdata"
sh "make markdown-init"
}
stage("docker pms") {
sh 'make build'
}
stage("docker biz") {
sh 'make build-biz'
sh 'make build-biz-k8s'
}
stage("docker max") {
sh 'make build-max'
sh 'make build-max-k8s'
}
stage("docker ipd") {
sh 'make build-ipd'
sh 'make build-ipd-k8s'
}
sh 'make markdown-render > ./report.md'
}
}
script {
job.unStashMsgHeader()
ximNotify(title: "禅道镜像构建成功", contentFile: "report.md", contentHeaderFile: job.headerFileName())
}
}
} // End Docker Image
stage("Upload rongpm") {
agent {
kubernetes {
inheritFrom "zentao-package xuanim"
yamlFile 'misc/ci/normal.yaml'
}
}
when {
allOf {
environment name:'PUBLISH_ZIP', value:'true'
environment name:'BUILD_KIND', value:'release'
}
beforeAgent true
}
environment {
OBJECT_KEY_PREFIX = "zentao/"
QINIU_ACCESS_KEY = credentials('qiniu-upload-ak')
QINIU_SECRET_KEY = credentials('qiniu-upload-sk')
}
steps {
script {
checkout scmGit(branches: [[name: "master"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/web/rongpm.git']]
)
container('package') {
sh 'mkdir -p output/rongpm/${PMS_VERSION}'
sh 'cd output/rongpm/${PMS_VERSION} && php7.2 $WORKSPACE/system/bin/buildpractice.php && rm -rf rongpm'
}
container('jnlp') {
sh 'qshell account $QINIU_ACCESS_KEY $QINIU_SECRET_KEY uploader'
sh 'qshell qupload2 --bucket $QINIU_BUCKET --overwrite --src-dir ./output --key-prefix $OBJECT_KEY_PREFIX'
}
}
}
} // End Upload rongpm
}
} // end publish
}
post {
failure {
ximNotify(title: "禅道构建失败", content: "请点击查看详情")
}
}
}
+464
View File
@@ -0,0 +1,464 @@
pipeline {
agent {
kubernetes {
inheritFrom "xuanim"
yamlFile 'misc/ci/normal.yaml'
}
}
options {
skipDefaultCheckout()
}
environment {
TZ="Asia/Shanghai"
ZENTAO_RELEASE_PATH = "${WORKSPACE}/release"
XUANXUAN_SRC_PATH = "${WORKSPACE}/xuansrc"
SRC_ZDOO_PATH = "${WORKSPACE}/zdoo"
SRC_ZDOOEXT_PATH = "${WORKSPACE}/zdooext"
SRC_ZENTAOEXT_PATH = "${WORKSPACE}/zentaoext"
MIDDLE_IMAGE_REPO = "hub.qc.oop.cc/zentao-package-ext"
MIDDLE_IMAGE_TAG = """${sh(
returnStdout: true,
script: 'date +%Y%m%d%H%M-${BUILD_ID}'
).trim()}"""
MIRROR = "true"
BUILD_BASIC = "true"
PUBLISH_ZIP = "true"
PUBLISH_IMAGE = "true"
PUBLISH_ZBOX = "true"
// set to blank for auto-detect from ci.json
DOWNGRADE_ENABLED = "false"
DOWNGRADE_VERSIONS = ""
}
stages {
stage("Basic Build") {
agent {
kubernetes {
inheritFrom "zentao-package build-docker xuanim"
yamlFile 'misc/ci/basic-build.yaml'
}
}
stages {
stage("Pull") {
steps {
checkout scm
script {
env.XUANVERSION = sh(returnStdout: true,script: 'jq -r .pkg.xuanxuan.gitVersion < ci.json').trim()
env.ZENTAOEXT_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zentaoext.gitVersion < ci.json').trim()
env.ZENTAOEXT_GIT_REPO = sh(returnStdout: true,script: 'jq -r .pkg.zentaoext.gitRepo < ci.json').trim()
env.ZDOO_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zdoo.gitVersion < ci.json').trim()
env.ZDOOEXT_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zdooext.gitVersion < ci.json').trim()
}
dir('xuansrc') {
checkout scmGit(branches: [[name: "${env.XUANVERSION}"]],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/easycorp/xuanxuan.git']]
)
}
dir('zdoo') {
checkout scmGit(branches: [[name: "${env.ZDOO_VERSION}"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/easycorp/zdoo.git']]
)
}
dir('zdooext') {
checkout scmGit(branches: [[name: "${env.ZDOOEXT_VERSION}"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/easycorp/zdooext.git']]
)
}
dir('zentaoext') {
checkout scmGit(branches: [[name: "${env.ZENTAOEXT_VERSION}"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: "${env.ZENTAOEXT_GIT_REPO}"]]
)
}
}
}
stage("Setup Global Env") {
steps {
script {
env.GIT_URL = sh(returnStdout: true, script: 'git config --get remote.origin.url').trim()
env.GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
env.GIT_TAG_BUILD_TYPE = 'snapshot'
env.GIT_TAG_BUILD_GROUP = sh(returnStdout: true, script: 'echo `date +%Y%m%d`.devops').trim()
env.GIT_TAGGER_NAME = sh(returnStdout: true, script: 'git show -s --format=%an').trim()
env.CI_PUBLIC_IMAGE_NAMESPACE = sh(returnStdout: true,script: 'jq -r .image.public.namespace.' + env.GIT_TAG_BUILD_TYPE + ' < ci.json').trim()
env.CI_INTERNAL_IMAGE_NAMESPACE = sh(returnStdout: true,script: 'jq -r .image.internal.namespace.' + env.GIT_TAG_BUILD_TYPE + ' < ci.json').trim()
// def ximUsers = sh(returnStdout: true,script: 'jq -r .notice.users < ci.json').trim()
env.XIM_USERS = 'qishiyao,zhaoke,zhengyuansheng'
// env.XIM_GROUPS = sh(returnStdout: true,script: 'jq -r .notice.groups < ci.json').trim()
env.PMS_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/VERSION').trim()
env.BIZ_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/BIZVERSION').trim()
env.MAX_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/MAXVERSION').trim()
env.IPD_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/IPDVERSION').trim()
env.CI_DOWNGRADE_ENABLED = sh(returnStdout: true, script: 'test -n "${DOWNGRADE_ENABLED}" && echo ${DOWNGRADE_ENABLED} || (jq -r .downgrade.enabled < ci.json)').trim()
env.QINIU_BUCKET = sh(returnStdout: true, script: 'jq -r .upload.bucket < ci.json').trim()
env.ARTIFACT_REPOSITORY = sh(returnStdout: true, script: 'misc/parse_tag.sh $TAG_NAME type | grep release >/dev/null && echo easycorp || echo easycorp-snapshot').trim()
env.ARTIFACT_HOST = "nexus.qc.oop.cc"
env.ARTIFACT_PROTOCOL = "https"
env.ARTIFACT_CRED_ID = "nexus-jenkins"
}
}
}
stage("Build") {
when {
environment name:'BUILD_BASIC', value:'true'
}
stages {
stage("make ciCommon") {
steps {
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --title "`echo -n 5byA5aeL5p6E5bu656aF6YGT | base64 --decode`" --url "${BUILD_URL}" --content "Build by Tag ${TAG_NAME}" --debug --custom'
}
withCredentials([gitUsernamePassword(credentialsId: 'git-zcorp-cc-jenkins-bot-http',gitToolName: 'git-tool')]) {
container('package') {
sh 'mkdir ${ZENTAO_RELEASE_PATH} && chown 1000:1000 ${ZENTAO_RELEASE_PATH}'
sh 'git config --global pull.ff only'
sh 'cp -av ${ZENTAO_BUILD_PATH}/adminer www/'
sh 'pwd && ls -l && make ciCommon'
sh 'ls -l ${ZENTAO_RELEASE_PATH}'
}
}
}
}
stage("zentaoext") {
steps {
container('package') {
sh 'cd $SRC_ZENTAOEXT_PATH && make'
sh 'cp ${ZENTAO_BUILD_PATH}/zentao*.zip ./'
sh 'cp ${ZENTAO_BUILD_PATH}/docker/Dockerfile.release.ext ./Dockerfile.release.ext'
}
container('docker') {
sh 'docker build --pull -t ${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG} -f Dockerfile.release.ext ${ZENTAO_RELEASE_PATH}'
sh 'docker push ${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}'
}
}
}
}
} // End Build
}
}
stage("Publish") {
environment {
OUTPUT_PKG_PATH = "${ZENTAO_RELEASE_PATH}/output"
}
stages {
stage("Merge and Upload") {
when {
environment name:'PUBLISH_ZIP', value:'true'
}
matrix {
agent {
kubernetes {
containerTemplate {
name "package"
image "${MIDDLE_IMAGE_REPO}:${MIDDLE_IMAGE_TAG}"
command "sleep"
args "99d"
}
}
}
options {
skipDefaultCheckout()
}
axes {
axis {
name "ZLANG"
values "cn"
}
axis {
name "PHPVERSION"
values "k8s.php8.1"
}
}
excludes {
exclude {
axis {
name 'ZLANG'
values 'en'
}
axis {
name "PHPVERSION"
values "k8s.php7.2_7.4", "k8s.php8.1"
}
}
}
stages {
stage("ZIP") {
environment {
ARTIFACT_NAME = """${sh(
returnStdout: true,
script: 'test ${ZLANG} = cn && echo -n ZenTaoPMS || echo -n ZenTaoALM'
).trim()}"""
INT_FLAG = """${sh(
returnStdout: true,
script: 'test ${ZLANG} = cn && echo -n "int." || echo -n ""'
).trim()}"""
}
stages {
stage("package zip") {
steps{
echo "${env.ZLANG} <=> ${env.PHPVERSION}"
container('package') {
sh 'mkdir $ZENTAO_RELEASE_PATH'
sh '${ZENTAO_BUILD_PATH}/package.sh zip'
sh 'mkdir $OUTPUT_PKG_PATH'
}
}
}
stage("upload zip") {
steps {
nexusArtifactUploader(
nexusVersion: 'nexus3',
protocol: env.ARTIFACT_PROTOCOL,
nexusUrl: env.ARTIFACT_HOST,
groupId: 'zentao.pmsPack' + '.' + env.GIT_TAG_BUILD_GROUP,
version: env.PMS_VERSION,
repository: env.ARTIFACT_REPOSITORY,
credentialsId: env.ARTIFACT_CRED_ID,
artifacts: [
[artifactId: env.ARTIFACT_NAME,
classifier: env.PHPVERSION,
file: env.ZENTAO_RELEASE_PATH + '/base.zip',
type: 'zip']
]
)
sh 'mkdir ${OUTPUT_PKG_PATH}/${PMS_VERSION}'
sh 'cp ${ZENTAO_RELEASE_PATH}/base.zip ${OUTPUT_PKG_PATH}/${PMS_VERSION}/${ARTIFACT_NAME}-${PMS_VERSION}-${PHPVERSION}.zip'
script {
def pkgVersionMap = [
"biz": ["bizPack", env.BIZ_VERSION],
"max": ["maxPack", env.MAX_VERSION],
"ipd": ["ipdPack", env.IPD_VERSION]
]
for (entry in pkgVersionMap.entrySet()) {
echo "set ExtName to ${entry.key}"
def ExtName = entry.key
echo "set SubGroup to ${entry.value[0]}"
def SubGroup = entry.value[0]
echo "set Zversion to ${entry.value[1]}"
def Zversion = entry.value[1]
nexusArtifactUploader(
nexusVersion: 'nexus3',
protocol: env.ARTIFACT_PROTOCOL,
nexusUrl: env.ARTIFACT_HOST,
groupId: 'zentao.' + SubGroup + '.' + env.GIT_TAG_BUILD_GROUP,
version: Zversion,
repository: env.ARTIFACT_REPOSITORY,
credentialsId: env.ARTIFACT_CRED_ID,
artifacts: [
[artifactId: env.ARTIFACT_NAME,
classifier: env.PHPVERSION,
file: env.ZENTAO_RELEASE_PATH + '/' + ExtName + '.zip',
type: 'zip'],
[artifactId: env.ARTIFACT_NAME,
classifier: 'update.' + env.PHPVERSION,
file: env.ZENTAO_RELEASE_PATH + '/' + ExtName + '.update.zip',
type: 'zip']
]
)
sh 'mkdir ${OUTPUT_PKG_PATH}/' + Zversion
def moveCmd1 = String.format('mv ${ZENTAO_RELEASE_PATH}/%s.zip ${OUTPUT_PKG_PATH}/%s/${ARTIFACT_NAME}-%s-${PHPVERSION}.zip', ExtName, Zversion, Zversion)
sh moveCmd1
def moveCmd2 = String.format('mv ${ZENTAO_RELEASE_PATH}/%s.update.zip ${OUTPUT_PKG_PATH}/%s/${ARTIFACT_NAME}-%s-update.${PHPVERSION}.zip', ExtName, Zversion, Zversion)
sh moveCmd2
} // End for loop
}
}
} // End upload zip
stage("syspack") {
when {
// buildingTag()
environment name: 'GIT_TAG_BUILD_TYPE', value: 'release'
}
steps{
sh 'env | grep GIT_TAG'
container('package') {
sh '${ZENTAO_BUILD_PATH}/package.sh deb'
sh '${ZENTAO_BUILD_PATH}/package.sh rpm'
}
}
}
stage("upload syspack") {
when {
environment name: 'GIT_TAG_BUILD_TYPE', value: 'release'
}
steps {
sh 'mv ${ZENTAO_RELEASE_PATH}/zentao.rpm ${OUTPUT_PKG_PATH}/${PMS_VERSION}/${ARTIFACT_NAME}-${PMS_VERSION}-${PHPVERSION}-1.noarch.rpm'
sh 'mv ${ZENTAO_RELEASE_PATH}/zentao.deb ${OUTPUT_PKG_PATH}/${PMS_VERSION}/${ARTIFACT_NAME}_${PMS_VERSION}-${PHPVERSION}-1_all.deb'
}
} // End upload syspack cn
stage("Upload Qiniu") {
when {
environment name: 'GIT_TAG_BUILD_TYPE', value: 'release'
}
environment {
OBJECT_KEY_PREFIX = "zentao/"
QINIU_ACCESS_KEY = credentials('qiniu-upload-ak')
QINIU_SECRET_KEY = credentials('qiniu-upload-sk')
}
steps {
sh 'ls -l ${OUTPUT_PKG_PATH}'
container('jnlp') {
sh 'qshell account $QINIU_ACCESS_KEY $QINIU_SECRET_KEY uploader'
sh 'qshell qupload2 --bucket $QINIU_BUCKET --overwrite --src-dir $OUTPUT_PKG_PATH --key-prefix $OBJECT_KEY_PREFIX'
}
}
}
} // end stages
} // end stage frame
} // End matrix stages
} // End matrix
} // End Merge and Upload Max
stage("Notice ZIP") {
when {
environment name:'PUBLISH_ZIP', value:'true'
}
steps {
checkout scmGit(branches: [[name: "master"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/devops/zentao-package.git']]
)
container('xuanimbot') {
sh 'env | grep GIT'
sh 'git config --global --add safe.directory $(pwd)'
sh './gen_build_report.sh > success.md'
sh '/usr/local/bin/xuanimbot --title "`echo -n 56aF6YGT5rqQ56CB5YyF5p6E5bu65oiQ5Yqf | base64 --decode`" --url "${RUN_DISPLAY_URL}" --content-file success.md --debug --custom'
}
}
}
stage("Docker Image") {
when {
environment name:'PUBLISH_IMAGE', value:'true'
}
agent {
kubernetes {
inheritFrom "dind xuanim"
yamlFile 'misc/ci/publish-image.yaml'
}
}
environment {
REGISTRY_HOST="hub.zentao.net"
CI_BUILD_PUBLIC_IMAGE="true"
CI_PHP_VER="8.1.23"
}
stages() {
stage("prepare") {
steps {
sh 'env'
checkout scmGit(branches: [[name: "master"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/app/zentao.git']]
)
container('docker') {
sh "sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories"
sh "apk --no-cache add make bash jq git tzdata"
sh "make markdown-init"
}
}
}
stage("docker ipd") {
environment {
ZENTAO_URL = """${sh(
returnStdout: true,
script: "echo ${ARTIFACT_PROTOCOL}://${ARTIFACT_HOST}/repository/${ARTIFACT_REPOSITORY}/zentao/ipdPack/`echo ${GIT_TAG_BUILD_GROUP} | tr . /`/ZenTaoPMS"
).trim()}"""
}
steps {
container('docker') {
withDockerRegistry(credentialsId: 'hub-qucheng-push', url: 'https://' + env.REGISTRY_HOST) {
sh "docker buildx create --name mybuilder --driver docker-container --bootstrap"
sh "docker buildx use mybuilder"
sh 'make build-ipd-k8s'
}
}
}
}
stage("Notice Image") {
steps {
container('docker') {
sh 'make markdown-render > ./report.md'
}
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --title "`echo -n 56aF6YGT6ZWc5YOP5p6E5bu65oiQ5Yqf | base64 --decode`" --url "${RUN_DISPLAY_URL}" --content-file ./report.md --debug --custom'
}
}
}
}
} // End Docker Image
}
post {
failure {
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh '/usr/local/bin/xuanimbot --title "zentaopms build failed" --url "${BUILD_URL}" --content "" --debug --custom'
}
}
}
} // end publish
}
}
+152
View File
@@ -0,0 +1,152 @@
pipeline {
agent {
kubernetes {
inheritFrom "xuanim"
yamlFile 'misc/ci/normal.yaml'
}
}
options {
skipDefaultCheckout()
}
environment {
TZ="Asia/Shanghai"
ZENTAO_RELEASE_PATH = "${WORKSPACE}/release"
XUANXUAN_SRC_PATH = "${WORKSPACE}/xuansrc"
SRC_ZDOO_PATH = "${WORKSPACE}/zdoo"
SRC_ZDOOEXT_PATH = "${WORKSPACE}/zdooext"
SRC_ZENTAOEXT_PATH = "${WORKSPACE}/zentaoext"
// set to blank for auto-detect from ci.json
DOWNGRADE_ENABLED = "false"
DOWNGRADE_VERSIONS = "7.2,7.1,7.0,5.4"
}
stages {
stage("Test Code") {
agent {
kubernetes {
inheritFrom "zentao-package build-docker xuanim"
yamlFile 'misc/ci/basic-build.yaml'
}
}
stages {
stage("Pull") {
steps {
checkout scm
script {
env.XUANVERSION = sh(returnStdout: true,script: 'jq -r .pkg.xuanxuan.gitVersion < ci.json').trim()
env.ZENTAOEXT_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zentaoext.gitVersion < ci.json').trim()
env.ZENTAOEXT_GIT_REPO = sh(returnStdout: true,script: 'jq -r .pkg.zentaoext.gitRepo < ci.json').trim()
env.ZDOO_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zdoo.gitVersion < ci.json').trim()
env.ZDOOEXT_VERSION = sh(returnStdout: true,script: 'jq -r .pkg.zdooext.gitVersion < ci.json').trim()
}
dir('xuansrc') {
checkout scmGit(branches: [[name: "${env.XUANVERSION}"]],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/easycorp/xuanxuan.git']]
)
}
dir('zdoo') {
checkout scmGit(branches: [[name: "${env.ZDOO_VERSION}"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/easycorp/zdoo.git']]
)
}
dir('zdooext') {
checkout scmGit(branches: [[name: "${env.ZDOOEXT_VERSION}"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: 'https://git.zcorp.cc/easycorp/zdooext.git']]
)
}
dir('zentaoext') {
checkout scmGit(branches: [[name: "${env.ZENTAOEXT_VERSION}"]],
extensions: [cloneOption(depth: 2, noTags: false, reference: '', shallow: true)],
userRemoteConfigs: [[credentialsId: 'git-zcorp-cc-jenkins-bot-http', url: "${env.ZENTAOEXT_GIT_REPO}"]]
)
}
}
}
stage("Setup Global Env") {
steps {
script {
def ximUsers = sh(returnStdout: true,script: 'jq -r .notice.users < ci.json').trim()
env.XIM_USERS = "qishiyao"
env.XIM_GROUPS = "31a0008b-6e3e-4b7f-9b7b-396a46b1f8f4"
env.PMS_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/VERSION').trim()
env.BIZ_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/BIZVERSION').trim()
env.MAX_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/MAXVERSION').trim()
env.IPD_VERSION = sh(returnStdout: true, script: 'cat ${SRC_ZENTAOEXT_PATH}/IPDVERSION').trim()
}
}
}
stage("Downgrade") {
stages {
stage("make Package") {
steps {
withCredentials([gitUsernamePassword(credentialsId: 'git-zcorp-cc-jenkins-bot-http',gitToolName: 'git-tool')]) {
container('package') {
sh 'mkdir ${ZENTAO_RELEASE_PATH} && chown 1000:1000 ${ZENTAO_RELEASE_PATH}'
sh 'git config --global pull.ff only'
sh 'pwd && ls -l && make ciCommon'
sh 'ls -l ${ZENTAO_RELEASE_PATH}'
}
}
}
}
stage("test downgrade") {
steps {
container('package') {
sh 'unzip -q ZenTaoPMS.${PMS_VERSION}.zip'
sh 'ls -l zentaopms'
sh './misc/downgrade.sh -p "$DOWNGRADE_VERSIONS" -r zentaopms -i -s -o "$ZENTAO_RELEASE_PATH" framework lib module/*'
}
container('package') {
sh 'mkdir /tmp/publishHtml'
sh 'test -f ${ZENTAO_RELEASE_PATH}/downgradeReport.html && cp ${ZENTAO_RELEASE_PATH}/downgradeReport.html /tmp/publishHtml/ || echo "No syntax error"'
}
publishHTML([
allowMissing: true,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: '/tmp/publishHtml',
reportFiles: 'downgradeReport.html',
reportName: 'DowngradeReport'
])
container('xuanimbot') {
sh 'git config --global --add safe.directory $(pwd)'
sh 'test -f $ZENTAO_RELEASE_PATH/downgradeReport.html && /usr/local/bin/xuanimbot --title "`echo -n 6ZmN57qn5aSx6LSl | base64 --decode`" --url "${RUN_DISPLAY_URL}" --content "[PHP Syntax Report]($BUILD_URL/DowngradeReport/)" --debug --custom || echo "No syntax found"'
}
}
}
}
} // End Downgrade
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Gt
values:
- "7"
containers:
- name: docker
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
+17
View File
@@ -0,0 +1,17 @@
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Lt
values:
- "8"
- weight: 50
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: DoesNotExist
+21
View File
@@ -0,0 +1,21 @@
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Gt
values:
- "7"
containers:
- name: docker
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
+36
View File
@@ -0,0 +1,36 @@
metadata:
labels:
ci-cpu-level: high
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Gt
values:
- "7"
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: ci-cpu-level
operator: In
values:
- high
topologyKey: "kubernetes.io/hostname"
containers:
- name: docker
image: docker:23.0.6-dind-alpine3.17
command: ["sleep"]
args: ["99d"]
volumeMounts:
- mountPath: /var/run/docker.sock
name: docker-socket
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
+11
View File
@@ -0,0 +1,11 @@
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: easycorp.io/cpu-spec
operator: Gt
values:
- "7"
+15
View File
@@ -0,0 +1,15 @@
{
"require-dev": {
"rector/rector": "0.15.*"
},
"scripts": {
"rector": [
"Composer\\Config::disableProcessTimeout",
"rector process --no-diffs --no-progress-bar"
],
"rector-nocache": [
"Composer\\Config::disableProcessTimeout",
"rector process --no-diffs --no-progress-bar --clear-cache"
]
}
}
+116
View File
@@ -0,0 +1,116 @@
<!DOCTYPE html>
<html>
<head>
<title>PHP Syntax Errors</title>
<style>
/* Custom styles */
.container {
padding: 20px;
}
.page-content {
margin-top: 20px;
}
table {
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
.active {
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h1>PHP Syntax Errors</h1>
<div id="navMenu"></div>
<div class="page-content">
<div id="tableContainer"></div>
</div>
</div>
<script>
const jsonData =
;
const navMenu = document.getElementById("navMenu");
const tableContainer = document.getElementById("tableContainer");
// Create navigation buttons
for (const version in jsonData.versions) {
const button = document.createElement("button");
button.textContent = version;
button.addEventListener("click", () => renderTable(version));
navMenu.appendChild(button);
}
// Render table based on version
const renderTable = (version) => {
const data = jsonData.versions[version];
const tableData = [];
for (let i = 0; i < data.length; i += 2) {
const fileName = data[i];
const errorDetails = data[i + 1];
tableData.push({ fileName, errorDetails });
}
const table = document.createElement("table");
const thead = document.createElement("thead");
const tbody = document.createElement("tbody");
const headerRow = document.createElement("tr");
const fileNameHeader = document.createElement("th");
fileNameHeader.textContent = "File Name";
const errorDetailsHeader = document.createElement("th");
errorDetailsHeader.textContent = "Error Details";
headerRow.appendChild(fileNameHeader);
headerRow.appendChild(errorDetailsHeader);
thead.appendChild(headerRow);
tableData.forEach((item) => {
const row = document.createElement("tr");
const fileNameCell = document.createElement("td");
fileNameCell.textContent = item.fileName;
const errorDetailsCell = document.createElement("td");
errorDetailsCell.textContent = item.errorDetails;
row.appendChild(fileNameCell);
row.appendChild(errorDetailsCell);
tbody.appendChild(row);
});
table.appendChild(thead);
table.appendChild(tbody);
// Clear previous table
tableContainer.innerHTML = "";
// Append new table
tableContainer.appendChild(table);
// Update active button
const buttons = navMenu.getElementsByTagName("button");
for (const button of buttons) {
button.classList.remove("active");
}
Array.from(buttons).forEach((button) => {
if (button.textContent === version) {
button.classList.add("active");
}
});
};
// Initialize the page
const initialVersion = Object.keys(jsonData.versions)[0];
renderTable(initialVersion);
</script>
</body>
</html>
+386
View File
@@ -0,0 +1,386 @@
#!/bin/bash
set -e
phpVer="7.4"
installRector="false"
statisticSyntax="false"
codeRootDir=$PWD
composerDir="$(dirname "$(realpath "$0")")"
outputDir="$PWD/tmp"
reportHtmlFile="$PWD/misc/downgrade-report-tpl.html"
helper() {
cat << EOF
Usage: $0 -p version dirs...
Arguments:
-p php版本号,如 7.4
可以指定多个版本,用逗号分隔,如 7.4,7.0,5.4
-i 在 misc 目录执行 composer install, 安装 rector
-r 指定要降级的代码根目录, 默认为当前目录
-s 校验语法时不中断, 生成统计报告
-o 降级补丁包输出目录
EOF
}
# 处理命令行参数, 获取要降级的目录
[ $# -eq 0 ] && helper
while getopts "isr:p:o:" opt; do
case $opt in
"p")
phpVer=$OPTARG
;;
"r")
codeRootDir=$(realpath "$OPTARG")
;;
"i")
installRector="true"
;;
"s")
statisticSyntax="true"
;;
"o")
outputDir=$OPTARG
;;
*)
helper
exit 1
;;
esac
done
shift $((OPTIND - 1))
statisticDataFile="$outputDir/statistic.data.json"
if [ "$#" -eq 0 ];then
echo "need at least one file or directory"
exit 2
fi
# 处理降级目录路径
downGradeDirs=()
for d in "$@"
do
targetDir="$codeRootDir/$d"
test -d "$targetDir" || (echo "$d ($targetDir) is not a directory, abort."; exit 2)
downGradeDirs+=("${targetDir}")
done
# 结束命令行参数处理
excludeRegexList=(
lib/purifier/HTMLPurifier.autoload-legacy.php
lib/sqlparser/vendor/
lib/phpaes/phpseclib/
)
##################################
# 在非容器环境,返回 cpu 核数减一
# 在容器环境,如未对 cpu 做限制,返回宿主机核数减一,否则按实际限制的 cpu 核数
##################################
quotaFile="/sys/fs/cgroup/cpu.max"
getCpuQuota() {
if [ -f $quotaFile ];then
quota=$(cut -d ' ' -f 1 $quotaFile)
period=$(cut -d ' ' -f 2 $quotaFile)
if [ "$quota" = "max" ];then
echo $(($(nproc)-1))
return
else
echo $((quota/period))
return
fi
else
echo $(($(nproc)-1))
return
fi
}
# 检查要降级版本的 php 命令行是否存在,将用于校验语法
existsPHPCli() {
phpVersion="$1"
which php"${phpVersion}" >/dev/null
}
#########################################
# 执行降级命令
# 参数:
# 1. 降级版本, 如 7.4, 7.0
# 2. 关闭缓存 (可选项), nocache
# 3. 并行执行 (可选项), parallel
# * 降级目录列表
# 说明
# 1. 由于降级命令有可能会发生异常,故设置了重试,
# 在函数运行时,缓存目录不变,故重试时会减少部分时间
# 2. 并行执行的个数,根据 cpu 最大核数减一处理,如果是容器环境,按分配的核数
# 并行执行需要安装 parallel 包
##########################################
maxRectorRetries=3
downGradeDir() {
rectorCmd="rector"
export PHP_VERSION=${1/./}
shift
if [ "$1" = "nocache" ];then
rectorCmd="rector-nocache"
shift
fi
withParallel="false"
if [ "$1" = "parallel" ];then
withParallel="true"
shift
fi
downDirs=("$@")
echo "set PHP_VERSION to $PHP_VERSION"
echo "do downgrade on dir ${downDirs[*]}"
lastDir=$PWD
cd "$composerDir" || exit
rectorResult=0
set +e
for ((i=0;i<maxRectorRetries;i++)) {
if [ "$withParallel" = "true" ];then
quotaCpu=$(getCpuQuota)
parallel -j "$quotaCpu" -k composer "${rectorCmd}" ::: "${downDirs[@]}"
else
composer ${rectorCmd} -- "${downDirs[@]}"
fi
rectorResult="$?"
if [ "$rectorResult" -eq 0 ];then
break
fi
}
set -e
if [ "$rectorResult" -ne 0 ];then
echo "Rector failed"
return $rectorResult
fi
cd "$lastDir" || exit
}
############################
# 校验单个 php 文件语法
# 返回值
# 0 没有语法错误
# 1 语法异常,或是执行时异常
############################
syntaxCheck() {
phpVersion="$1"
phpFilePath="$2"
phpCli=$(which php"${phpVersion}")
$phpCli -l "$phpFilePath" | grep -v 'No syntax errors detected' && return 1 || return 0
}
########################################
# 确保php文件语法正确
# 第一次校验失败后,对文件所在目录执行一次降级
# 再做第二次校验,如继续失败,返回错误
########################################
ensureSyntaxPassed() {
phpVersion="$1"
phpFilePath="$2"
beforeMD5=$(md5sum "$phpFilePath" | awk '{print $1}')
if syntaxCheck "$phpVersion" "$phpFilePath";then
echo "Syntax OK, $phpFilePath"
else
downGradeDir "$phpVersion" "nocache" "$(dirname "$phpFilePath")"
afterMD5=$(md5sum "$phpFilePath" | awk '{print $1}')
if ! syntaxCheck "$phpVersion" "$phpFilePath";then
echo "downgrade failed"
echo "md5 compare (before:$beforeMD5) (after:$afterMD5)"
if [[ "$statisticSyntax" == "true" ]];then
syntaxAddErrRecord "$phpVersion" "$phpFilePath"
return 0
else
return 1
fi
else
echo "Syntax OK, $phpFilePath"
fi
fi
}
#########################################
# 将变更的文件打包
# 判断条件为文件修改时间晚于脚本开始执行的时间
#########################################
archiveChangedFiles() {
phpVersion="$1"
pointTime=$2
archiveDir=$3
find "$archiveDir" -type f -name '*.php' -newermt "$pointTime" -printf "%P\n" > /tmp/changedFiles
lastDir=$PWD
cd "$archiveDir" || exit 1
mkdir -p build/
test -d "$outputDir" || mkdir -pv "$outputDir"
downPatchFile="${outputDir}/downgrade-php$phpVersion.tar.gz"
tar zcf "$downPatchFile" --files-from=/tmp/changedFiles
echo "Release downgrade patch file: $downPatchFile"
cd "$lastDir"
}
# 正则匹配要排除的文件,跳过校验
matchExclude() {
filePath="$1"
for reg in "${excludeRegexList[@]}"
do
if [[ "$filePath" =~ $reg ]];then
echo "true"
return
fi
done
echo "false"
}
#############################
# 对单个 php 版本降级的主函数
# 参数:
# 1. php 版本
# 2. 起始时间, 用于比较降级后变更的文件
# * 降级目录列表
# 步骤:
# 设置临时缓存目录,执行降级
# 对降级目录里所有 php 文件校验语法,确保通过
# 打包变更文件
########################################
DownGrade() {
phpVersion="$1"
pointTime="$2"
shift 2
downDirs=("$@")
RECTOR_CACHE_DIR=$(mktemp -d)
export RECTOR_CACHE_DIR
startTime="$(date +%s)"
if which parallel >/dev/null ;then
downGradeDir "$phpVersion" parallel "${downDirs[@]}"
else
for d in "${downDirs[@]}"
do
downGradeDir "$phpVersion" "$d"
done
fi
for f in $(find "${downGradeDirs[@]}" -type f -name '*.php')
do
shouldIgnore=$(matchExclude "$f")
if [ "$shouldIgnore" = "true" ];then
echo "$f is excluded"
continue
fi
ensureSyntaxPassed "$phpVersion" "$f"
done
archiveChangedFiles "$phpVersion" "$pointTime" "$codeRootDir"
test -d "$RECTOR_CACHE_DIR" && rm -rf "$RECTOR_CACHE_DIR"
endTime="$(date +%s)"
echo "downgrade to ${phpVersion} cost $((endTime-startTime)) seconds"
echo
}
syntaxInitReport() {
echo '{"versions": {}}' > "$statisticDataFile"
}
syntaxAddErrRecord() {
phpVersion="$1"
phpFilePath="$2"
phpCli=$(which php"${phpVersion}")
listKey=".versions[\"$phpVersion\"]"
fileName=$(echo "$phpFilePath"| sed "s|${codeRootDir}/||")
lastDir=$PWD
cd "$codeRootDir" || exit 1
set +e
errMsg=$($phpCli -l "$fileName" | jq -Rs '.')
set -e
cd "$lastDir"
jq "$listKey += [\"$fileName\", $errMsg]" "$statisticDataFile" > "$statisticDataFile.tmp"
mv "$statisticDataFile.tmp" "$statisticDataFile"
}
preProcess() {
# 初始化语法错误记录
if [[ "$statisticSyntax" == "true" ]];then
syntaxInitReport
fi
# 执行 composer 组件安装
if [ "$installRector" = "true" ];then
lastDir=$PWD
cd "$composerDir" || exit 1
composer config -g repo.packagist composer https://mirrors.cloud.tencent.com/composer/
composer install
cd "$lastDir" || exit 1
fi
}
process() {
# 设置脚本启动时间
startPointTime=$(date +'%Y-%m-%d %H:%M:%S')
# 检查 -p 参数, 执行多版本降级或是单版本降级
if [[ "$phpVer" =~ ^.*, ]];then
IFS=',' read -r -a verList <<< "$phpVer"
for v in "${verList[@]}"
do
existsPHPCli "$v" || (echo "php${v} is not found, abort."; exit 3)
done
for v in "${verList[@]}"
do
DownGrade "$v" "$startPointTime" "${downGradeDirs[@]}"
done
else
existsPHPCli "$phpVer" || (echo "php${phpVer} is not found, abort."; exit 3)
DownGrade "$phpVer" "$startPointTime" "${downGradeDirs[@]}"
fi
}
postProcess() {
if [[ "$statisticSyntax" == "true" ]];then
foundSyntaxErr="false"
for ver in $(jq -r '.versions | keys[]' "$statisticDataFile")
do
count=$(jq -r ".versions[\"$ver\"] | length" < "$statisticDataFile")
if [[ "$count" -gt 0 && "$foundSyntaxErr" != "true" ]];then
foundSyntaxErr=true
fi
done
if [[ "$foundSyntaxErr" == "true" ]];then
reportInsertLine=$(grep -n 'const jsonData' "$reportHtmlFile" | cut -d: -f1)
jq -c . "$statisticDataFile" | sed "${reportInsertLine}r /dev/stdin" "$reportHtmlFile" > "$outputDir/downgradeReport.html"
fi
fi
}
preProcess
process
postProcess
# syntaxCheck "$phpVer" /code/module/pipeline/model.php
# downGradeDir "$phpVer" "${downGradeDirs[@]}"
# archiveChangedFiles "$t" "$codeRootDir"
+37
View File
@@ -0,0 +1,37 @@
#!/bin/bash
TAG=$1
FIELD=$2
frameCount=`echo $TAG| grep -o '_' | wc -l`
build_id=''
if [ $frameCount -eq 3 ];then
build_id=`echo $TAG | cut -d _ -f 3`
fi
case $FIELD in
group)
case $frameCount in
1)
echo release
;;
*)
build_date=${TAG##*_}
if [ -n "$build_id" ];then
echo "$build_date.$build_id"
else
echo "$build_date.release"
fi
;;
esac
;;
type)
if [ -n "$build_id" ];then
echo snapshot
else
echo release
fi
;;
esac
+23
View File
@@ -0,0 +1,23 @@
<?php
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\DowngradeLevelSetList;
use Rector\Set\ValueObject\DowngradeSetList;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Caching\ValueObject\Storage\FileCacheStorage;
$version = getenv('PHP_VERSION');
$version = $version ?: '72';
$cacheDir = getenv('RECTOR_CACHE_DIR');
$cacheDir = $cacheDir ?: '/tmp/rector_cached_files';
return static function (RectorConfig $rectorConfig) use ($version,$cacheDir): void {
$rectorConfig->skip([
'test/*',
]);
$rectorConfig->phpVersion(constant(PhpVersion::class . '::PHP_' . $version));
$rectorConfig->sets([constant(DowngradeLevelSetList::class . '::DOWN_TO_PHP_' . $version)]);
// $rectorConfig->sets([constant(DowngradeSetList::class . '::PHP_' . $version)]);
$rectorConfig->cacheClass(FileCacheStorage::class);
$rectorConfig->cacheDirectory($cacheDir);
};