import org.jenkinsci.plugins.pipeline.modeldefinition.Utils def call(String baseImage = "ubuntu:22.04") { node { stage("Checkout project") { checkout(scm) } stage('Run in Symfony image') { def symfonyImage = buildDockerImage(baseImage) symfonyImage.inside() { def repo = env.JOB_NAME if (env.BRANCH_NAME ==~ /^PR-.*$/) { repo = env.JOB_NAME - "/${env.JOB_BASE_NAME}" } stage("Install composer dependencies") { sh ''' composer install ''' } parallel([ 'php-security-check': { stage("Check PHP security issues") { catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { def auditReport = sh(script: "local-php-security-checker --format=markdown || true", returnStdout: true) if (auditReport.trim() != "") { if (env.CHANGE_ID) { gitea.commentPullRequest(repo, env.CHANGE_ID, auditReport, 0) } else { print auditReport } } if (!auditReport.contains("No packages have known vulnerabilities.")) { throw new Exception("Dependencies check failed !") } } } }, 'php-cs-fixer': { stage("Run PHP-CS-Fixer on modified code") { catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { if ( !fileExists('.php-cs-fixer.dist.php') ) { def phpCsFixerConfig = libraryResource 'com/cadoles/symfony/.php-cs-fixer.dist.php' writeFile file:'.php-cs-fixer.dist.php', text:phpCsFixerConfig } sh ''' CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "HEAD~..HEAD" | fgrep ".php" | tr "\n" " ") if ! echo "${CHANGED_FILES}" | grep -qE "^(\\.php-cs-fixer(\\.dist)\\.php?|composer\\.lock)$"; then EXTRA_ARGS=$(printf -- '--path-mode=intersection -- %s' "${CHANGED_FILES}"); else EXTRA_ARGS=''; fi php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --dry-run --using-cache=no --format junit ${EXTRA_ARGS} > php-cs-fixer.xml || true ''' def report = sh(script: "junit2md php-cs-fixer.xml", returnStdout: true) if (env.CHANGE_ID) { gitea.commentPullRequest(repo, env.CHANGE_ID, report, 1) } else { print report } } } }, 'phpstan': { stage("Run phpstan") { catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { if ( !fileExists('phpstan.neon') ) { def phpStanConfig = libraryResource 'com/cadoles/symfony/phpstan.neon' writeFile file:'phpstan.neon', text:phpStanConfig } sh ''' phpstan analyze -l 1 --error-format=table src > phpstan.txt || true ''' def report = sh(script: "cat phpstan.txt", returnStdout: true) report = "## Rapport PHPStan\n\n```\n" + report report = report + "\n```\n" if (env.CHANGE_ID) { gitea.commentPullRequest(repo, env.CHANGE_ID, report, 2) } else { print report } } } } ]) } } } } def buildDockerImage(String baseImage) { def imageName = "cadoles-symfony-ci" dir (".${imageName}") { def dockerfile = libraryResource 'com/cadoles/symfony/Dockerfile' writeFile file:'Dockerfile', text: "FROM ${baseImage}\n\n" + dockerfile def addLetsEncryptCA = libraryResource 'com/cadoles/common/add-letsencrypt-ca.sh' writeFile file:'add-letsencrypt-ca.sh', text:addLetsEncryptCA def safeJobName = URLDecoder.decode(env.JOB_NAME).toLowerCase().replace('/', '-').replace(' ', '-') def imageTag = "${safeJobName}-${env.BUILD_ID}" return docker.build("${imageName}:${imageTag}", ".") } } def when(boolean condition, body) { def config = [:] body.resolveStrategy = Closure.OWNER_FIRST body.delegate = config if (condition) { body() } else { Utils.markStageSkippedForConditional(STAGE_NAME) } }