J'ai écrit un fichier Jenkins à CI une application Gradle Java avec Jenkins. Lorsque je le transmets à Github, le travail de pipeline Jenkins sur AWS s'exécute, et si le test réussit, je l'utilise également comme un déploiement sur Tomcat sur AWS.
Declarative Pipeline En l'état, Jenkinsfile
node {
....
}
Il a été écrit comme, mais si vous regardez Site officiel de Jenkins Il s'agit de la notation Scripted Pipelines, À partir de la migration de la version 2.5 du plugin Pipeline
pipeline {
....
}
Une notation appelée Declarative Pipeline a été introduite pour écrire comme C'était plus simple et plus facile à écrire, alors je l'ai réécrit. C'est certainement chouette (surtout le dernier email, déploiement) C'est bien de pouvoir mélanger les pipelines scriptés traditionnels en cas d'urgence.
Jenkins non inclus dans le plugin suggéré au moment de la configuration initiale
Jenkinsfile Exécutez une tâche de pipeline Jenkins avec un webhook de Github. Pour les travaux de pipeline, utilisez Jenkinsfile de Github. Le flux des travaux est le suivant. Déployez uniquement si l'analyse et les tests de code statique réussissent.
Jenkinsfile
pipeline {
agent any
//Définir des constantes et des variables
environment {
reportDir = 'build/reports'
javaDir = 'src/main/java'
resourcesDir = 'src/main/resources'
testReportDir = 'build/test-results/test'
jacocoReportDir = 'build/jacoco'
javadocDir = 'build/docs/javadoc'
libsDir = 'build/libs'
appName = 'SampleApp'
appVersion = '1.0.0'
}
//Définir une ou plusieurs étapes dans le bloc étapes
stages {
stage('Préparation préalable') {
//Le traitement réel est défini dans le bloc étapes
steps {
deleteDir()
//Découvrez le projet Github qui a déclenché ce Job
checkout scm
//Jenkinsfile et build pour enquêter sur la cause de l'échec du travail.gradle enregistrer d'abord
archiveArtifacts "Jenkinsfile"
archiveArtifacts "build.gradle"
//Vous pouvez également utiliser la notation traditionnelle Scripted Pipelines avec le bloc de script
script {
//Accordez la permission d'exécution pour ne pas vous fâcher avec la permission refusée
if(isUnix()) {
sh 'chmod +x gradlew'
}
}
gradlew 'clean'
}
}
stage('compiler') {
steps {
gradlew 'classes testClasses'
}
//Le bloc post peut définir le processus à exécuter après le bloc étapes
post {
//Le bloc always est toujours exécuté, que le traitement du bloc d'étapes échoue ou réussisse.
always {
//Si vous l'exécutez lors de la génération de JavaDoc, l'avertissement JavaDoc sera également inclus.
//Les avertissements de compilation Java sont collectés immédiatement après la compilation
step([
//La spécification de classe lors de l'exécution du plug-in ne doit pas nécessairement être un nom complet
$class: 'WarningsPublisher',
//ConsoleParsers, si vous souhaitez collecter des alertes de la console lors de l'exécution de Job
// pmd.Spécifiez les configurations de l'analyseur lors de la collecte à partir d'un fichier tel que xml.
//Dans le cas des configurations d'analyseur, en plus du nom de l'analyseur, modèle(Chemin du fichier à agréger)Doit également être spécifié
//Utilisez le nom de l'analyseur défini dans le fichier de propriétés ci-dessous.
// https://github.com/jenkinsci/warnings-plugin/blob/master/src/main/resources/hudson/plugins/warnings/parser/Messages.properties
consoleParsers: [
[parserName: 'Java Compiler (javac)'],
],
canComputeNew: false,
canResolveRelativesPaths: false,
usePreviousBuildAsReference: true
])
}
}
}
stage('Analyse de code statique') {
steps {
//Utilisez la méthode parallèle pour le traitement parallèle
parallel(
'Analyse de code statique' : {
gradlew 'check -x test'
//Vous pouvez spécifier le répertoire actuel avec la méthode dir
dir(reportDir) {
step([
$class: 'CheckStylePublisher',
pattern: "checkstyle/*.xml"
])
step([
$class: 'FindBugsPublisher',
pattern: "findbugs/*.xml"
])
step([
$class: 'PmdPublisher',
pattern: "pmd/*.xml"
])
step([
$class: 'DryPublisher',
pattern: "cpd/*.xml"
])
archiveArtifacts "checkstyle/*.xml"
archiveArtifacts "findbugs/*.xml"
archiveArtifacts "pmd/*.xml"
archiveArtifacts "cpd/*.xml"
}
},
'Nombre de pas': {
//Création de rapports
//Si vous spécifiez outputFile et outputFormat, un fichier Excel sera également créé.
stepcounter outputFile: 'stepcount.xls', outputFormat: 'excel', settings: [
[key:'Java', filePattern: "${javaDir}/**/*.java"],
[key:'SQL', filePattern: "${resourcesDir}/**/*.sql"],
[key:'HTML', filePattern: "${resourcesDir}/**/*.html"],
[key:'JS', filePattern: "${resourcesDir}/**/*.js"],
[key:'CSS', filePattern: "${resourcesDir}/**/*.css"]
]
//Pour le moment, enregistrez le fichier Excel en tant que livrable
archiveArtifacts "stepcount.xls"
},
'Analyse des tâches': {
step([
$class: 'TasksPublisher',
pattern: './**',
//Est-il sensible à la casse lors de la recherche de cibles d'agrégation?
ignoreCase: true,
//Les chaînes de caractères à agréger peuvent être spécifiées pour chaque priorité
//Si vous en spécifiez plusieurs, spécifiez une chaîne de caractères séparés par des virgules.
high: 'System.out.System.err',
normal: 'TODO,FIXME,XXX',
])
},
'JavaDoc': {
gradlew 'javadoc -x classes'
step([
$class: 'JavadocArchiver',
//Index Javadoc.Spécifiez le chemin du dossier où se trouve html
javadocDir: "${javadocDir}",
keepAll: true
])
}
)
}
post {
always {
//Collecter les avertissements JavaDoc
step([
$class: 'WarningsPublisher',
consoleParsers: [
[parserName: 'JavaDoc Tool']
],
canComputeNew: false,
canResolveRelativesPaths: false,
usePreviousBuildAsReference: true
])
}
}
}
stage('tester') {
steps {
gradlew 'test jacocoTestReport -x classes -x testClasses'
junit "${testReportDir}/*.xml"
archiveArtifacts "${testReportDir}/*.xml"
//Générer un rapport de couverture (hors classe de test)
step([
$class: 'JacocoPublisher',
execPattern: "${jacocoReportDir}/*.exec",
exclusionPattern: '**/*Test.class'
])
}
}
stage('Déployer') {
//Vous pouvez spécifier les conditions d'exécution de l'étape dans le bloc when
when {
//Ne pas déployer sur l'analyse de code statique et l'échec du test
expression {currentBuild.currentResult == 'SUCCESS'}
}
steps {
gradlew 'jar'
archiveArtifacts "${libsDir}/${appName}-${appVersion}.jar"
gradlew 'war'
archiveArtifacts "${libsDir}/${appName}-${appVersion}.war"
deploy warDir: libsDir, appName: appName, appVersion: appVersion
}
}
}
//Si vous définissez un bloc de poste au même niveau que le bloc d'étapes
//Il est possible de définir le traitement une fois que toutes les étapes de traitement sont terminées.
post {
always {
//Supprimez enfin le contenu de l'espace de travail
deleteDir()
}
//Envoyez-vous un e-mail sauf si vous réussissez dans une rangée
//Quand le résultat change depuis la dernière fois
changed {
sendMail("${currentBuild.previousBuild.result} => ${currentBuild.currentResult}")
}
//Quand ça échoue
failure {
sendMail(currentBuild.currentResult)
}
//Lorsqu'il est instable (principalement lorsque le test échoue)
unstable {
sendMail(currentBuild.currentResult)
}
}
}
//Exécutez la commande Gradlew
def gradlew(command) {
if(isUnix()) {
sh "./gradlew ${command} --stacktrace"
} else {
bat "./gradlew.bat ${command} --stacktrace"
}
}
//Déployer
// args.répertoire de stockage warDir war
// args.appName Nom de l'application
// args.version de l'application appVersion
def deploy(Map args) {
//Chemin de la clé privée * Puisque le fichier est transféré vers le serveur Tomcat, il est nécessaire de stocker la clé privée quelque part dans le serveur Jenkins à l'avance.
def keyDir = '/var/lib/jenkins/.ssh/xxx'
//Adresse du serveur Tomcat et nom d'utilisateur
def webServerAddress = 'ecX-XX-XXX-X-X.xx-xxxx-x.xxxxxxxx'
def webServerUser = 'hoge-user'
def webServer = "${webServerUser}@${webServerAddress}"
def srcWar = "${args.appName}-${args.appVersion}.war"
def destWar = "${args.appName}.war"
//Transférer des fichiers et placer la guerre dans les applications Web de Tomcat
sh "sudo -S scp -i ${keyDir} ./${args.warDir}/${srcWar} ${webServer}:/home/ec2-user"
sh "sudo -S ssh -i ${keyDir} ${webServer} \"sudo cp /home/ec2-user/${srcWar} /usr/share/tomcat8/webapps/${destWar}\""
}
//Envoyer des e-mails à Gmail
def sendMail(result) {
mail to: "[email protected]",
subject: "${env.JOB_NAME} #${env.BUILD_NUMBER} [${result}]",
body: "Build URL: ${env.BUILD_URL}.\n\n"
}
build.gradle Jenkins lui-même exécute simplement les commandes Gradle et génère un rapport basé sur la sortie, donc L'application Java build.gradle de Gradle doit être capable d'exécuter les processus suivants. Créez également un wrapper Gradle pour ne pas avoir à installer Gradle avec Jenkins.
Par exemple,
build.gradle
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'checkstyle'
apply plugin: 'findbugs'
apply plugin: 'pmd'
apply plugin: 'jacoco'
ext {
appVersion = '1.0.0'
appName = 'SampleApp'
javaVersion = 1.8
defaultEncoding = 'UTF-8'
}
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
tasks.withType(AbstractCompile)*.options*.encoding = defaultEncoding
tasks.withType(GroovyCompile)*.groovyOptions*.encoding = defaultEncoding
mainClassName = 'jp.takumon.sapmleapp.App'
repositories {
mavenCentral()
}
dependencies {
//Liste des bibliothèques dépendantes
compile group: 'junit', name: 'junit', version: '4.12'
}
jar {
baseName = appName
version = appVersion
}
war {
baseName = appName
version = appVersion
}
checkstyle {
//Continuer le traitement ultérieur même s'il échoue
ignoreFailures = true
sourceSets = [sourceSets.main]
toolVersion = '7.6.1'
}
findbugs {
//Continuer le traitement ultérieur même s'il échoue
ignoreFailures = true
sourceSets = [sourceSets.main]
toolVersion = "3.0.1"
}
pmd {
//Continuer le traitement ultérieur même s'il échoue
ignoreFailures = true
sourceSets = [sourceSets.main]
}
tasks.withType(Pmd) {
reports {
xml.enabled = true
}
}
//Ajout de CPD (traitement de vérification de code en double) pour vérifier la tâche
check.doLast {
File outputDir = new File("$reportsDir/cpd/")
outputDir.mkdirs()
ant.taskdef(
name: 'cpd',
classname: 'net.sourceforge.pmd.cpd.CPDTask',
classpath: configurations.pmd.asPath)
ant.cpd(
minimumTokenCount: '100',
format: 'xml',
encoding: defaultEncoding,
outputFile: new File(outputDir, 'cpd.xml')
) {
fileset(dir: "src/main/java") {
include(name: '**/*.java')
}
}
}
javadoc {
failOnError = false
//À votre niveau préféré
options.memberLevel = JavadocMemberLevel.PRIVATE
}
test {
//Continuer le traitement ultérieur même s'il échoue
ignoreFailures = true
reports {
junitXml.enabled = true
}
}
jacoco {
toolVersion = '0.7.5.201505241946'
}
jacocoTestReport {
reports {
xml.enabled = true
}
//Exclure la classe de test du rapport de couverture
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it, exclude: ['**/*Test.class'])
})
}
}
task wrapper (type: Wrapper) {
gradleVersion = '3.4.1'
}
c'est tout.
Recommended Posts