Newer
Older
environment {
BLUE_OCEAN_URL = "https://jenkins.ozg-sh.de/blue/organizations/jenkins/goofy/detail/${env.BRANCH_NAME}/${env.BUILD_NUMBER}/pipeline"
RELEASE_REGEX = /\d+.\d+.\d+/
SNAPSHOT_REGEX = /\d+.\d+.\d+-SNAPSHOT/
options {
timeout(time: 1, unit: 'HOURS')
disableConcurrentBuilds()
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
stage('Check Version') {
steps {
script {
FAILED_STAGE = env.STAGE_NAME
def rootPom = readMavenPom file: 'pom.xml'
VERSION = rootPom.version
def serverPom = readMavenPom file: 'goofy-server/pom.xml'
def serverVersion = serverPom.parent.version
def clientPom = readMavenPom file: 'goofy-client/pom.xml'
def clientVersion = clientPom.parent.version
if(env.BRANCH_NAME == 'release'){
if ( !(VERSION ==~ RELEASE_REGEX) || !(serverVersion ==~ RELEASE_REGEX) || !(clientVersion ==~ RELEASE_REGEX)) {
error("Keine Release Version für Branch ${env.BRANCH_NAME}.")
}
} else {
if ( !(VERSION ==~ SNAPSHOT_REGEX) || !(serverVersion ==~ SNAPSHOT_REGEX) || !(clientVersion ==~ SNAPSHOT_REGEX)) {
error("Keine Snapshot Version für Branch ${env.BRANCH_NAME}.")
}
}
if( !(VERSION == serverVersion && VERSION == clientVersion)){
error("Versionen sind nicht identisch")
}
}
}
}
stage('Client') {
steps {
container("nodejs"){
script {
FAILED_STAGE=env.STAGE_NAME
sh 'npm --version'
dir('goofy-client') {
sh 'echo "registry=https://nexus.ozg-sh.de/repository/npm-proxy" >> ~/.npmrc'
sh 'echo "_auth=amVua2luczpQaihzX0ZNNFU5ZC8=" >> ~/.npmrc'
sh 'npm install --no-optional'
if (env.BRANCH_NAME == 'release') {
sh 'npm run ci-prodBuild'
}
else {
sh 'npm run ci-build'
}
sh 'npm run ci-test'
try {
if (env.BRANCH_NAME == 'master') {
withSonarQubeEnv('sonarqube-ozg-sh'){
sh 'npm run ci-sonar'
}
}
} catch (Exception e) {
unstable("SonarQube failed")
}
}
}
}
}
// post {
// always{
// junit testResults: 'goofy-client/test-report.xml', skipPublishingChecks: true
// }
// }
}
stage('Server') {
steps {
script {
FAILED_STAGE=env.STAGE_NAME
IMAGE_TAG = "${env.BRANCH_NAME}-${VERSION}"
println("IMAGE_TAG: ${IMAGE_TAG}")
container("maven-17"){
configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
sh 'mvn --version'
sh "mvn -s $MAVEN_SETTINGS -pl -goofy-client clean install spring-boot:build-image -Dspring-boot.build-image.imageName=docker.ozg-sh.de/goofy:${IMAGE_TAG} -Dspring-boot.build-image.publish -Dmaven.wagon.http.retryHandler.count=3"
}
try {
if (env.BRANCH_NAME == 'master') {
dir('goofy-server'){
withSonarQubeEnv('sonarqube-ozg-sh'){
sh 'mvn sonar:sonar'
}
}
}
} catch (Exception e) {
unstable("SonarQube failed")
}
}
}
}
post {
always{
junit testResults: '**/target/surefire-reports/*.xml', skipPublishingChecks: true
}
}
}
FAILED_STAGE = env.STAGE_NAME
}
container("k8s") {
configFileProvider([configFile(fileId: 'jenkins-kuby-kubeconfig', variable: 'KUBE_CONFIG')]) {
sh 'mkdir ~/.kube'
sh 'cp ${KUBE_CONFIG} ~/.kube/config'
}
sh 'helm version'
}
}
}
stage('E2E') {
failFast false
steps {
script {
def stageName = env.STAGE_NAME
def namespace = generateNamespaceName(stageName)
checkIfNamespaceExists(namespace)
parallel(
startGoofy: {
},
startPluto: {
startPluto(namespace, 'ea-values.yaml')
}
)
if(runTests(stageName, 'einheitlicher-ansprechpartner') != '0') {
}
post {
always {
publishHTML (target: [
allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: 'goofy-client/apps/goofy-e2e/reports/einheitlicher-ansprechpartner',
reportFiles: 'report.html',
reportName: "Goofy E2E-Tests EA"
])
if (env.E2E_FAILED) {
if (env.E2E_FAILED.contains(env.STAGE_NAME)) {
currentBuild.result = 'FAILURE'
}
}
}
}
}
stage('E2E-main') {
steps {
script {
def stageName = env.STAGE_NAME
def namespace = generateNamespaceName(stageName)
},
startPluto: {
startPluto(namespace, 'values.yaml')
shutdownEnvironment(namespace)
}
}
post {
always {
publishHTML (target: [
allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: 'goofy-client/apps/goofy-e2e/reports/main-tests',
reportFiles: 'report.html',
reportName: "Goofy E2E-Tests main"
])
if (env.E2E_FAILED) {
if (env.E2E_FAILED.contains(env.STAGE_NAME)) {
currentBuild.result = 'FAILURE'
}
}
if (env.E2E_FAILED) {
FAILED_STAGE = "E2E (${env.E2E_FAILED.substring(0, env.E2E_FAILED.length() - 2)})"
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
stage('Deploy Maven Artifacts to Nexus') {
when {
anyOf {
branch 'master'
branch 'release'
}
}
steps {
script {
FAILED_STAGE = env.STAGE_NAME
}
container('maven-17') {
configFileProvider([configFile(fileId: 'maven-settings', variable: 'MAVEN_SETTINGS')]) {
sh 'mvn -s $MAVEN_SETTINGS -pl -goofy-client -DskipTests deploy'
}
}
}
}
stage('Deploy Goofy') {
when {
anyOf {
branch 'master'
branch 'release'
}
}
steps {
script {
FAILED_STAGE = env.STAGE_NAME
}
container("docker") {
script {
withCredentials([usernamePassword(credentialsId: 'jenkins-docker-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
sh 'docker login docker.ozg-sh.de -u ${USER} -p ${PASSWORD}'
if (env.BRANCH_NAME == 'release') {
sh 'docker tag docker.ozg-sh.de/goofy:${IMAGE_TAG} docker.ozg-sh.de/goofy:latest'
sh 'docker push docker.ozg-sh.de/goofy:latest'
}
if (env.BRANCH_NAME == 'master') {
sh 'docker tag docker.ozg-sh.de/goofy:${IMAGE_TAG} docker.ozg-sh.de/goofy:snapshot-latest'
sh 'docker push docker.ozg-sh.de/goofy:snapshot-latest'
}
}
}
}
}
}
stage('Rollout (kiel-dev & ea-dev) | (kiel-test $ sl-test) Goofy') {
when {
anyOf {
branch 'master'
branch 'release'
}
}
steps {
script {
FAILED_STAGE = env.STAGE_NAME
}
container("k8s"){
script {
if (env.BRANCH_NAME == 'release') {
sh 'kubectl rollout restart deployment/goofy -n sh-kiel-test'
sh 'kubectl rollout status deployment/goofy -n sh-kiel-test'
sh 'kubectl rollout restart deployment/goofy -n sh-sl-test'
sh 'kubectl rollout status deployment/goofy -n sh-sl-test'
}
if (env.BRANCH_NAME == 'master') {
sh 'kubectl rollout restart deployment/goofy -n sh-kiel-dev'
sh 'kubectl rollout status deployment/goofy -n sh-kiel-dev'
sh 'kubectl rollout restart deployment/goofy -n sh-ea-dev'
sh 'kubectl rollout status deployment/goofy -n sh-ea-dev'
}
}
}
}
}
}
post {
failure {
script {
if (env.BRANCH_NAME == 'master') {
slackSend(color: "danger", message: "Goofy: Build Failed. Stage: ${FAILED_STAGE} Build-ID: <${BLUE_OCEAN_URL}|${env.BUILD_NUMBER}>")
}
}
}
Void checkIfNamespaceExists(String namespace) {
container("k8s") {
def namespaceList = sh (script: 'kubectl get namespaces', returnStdout: true)
if(namespaceList.contains(namespace)) {
error("Namespace: ${namespace} existiert bereits")
}
}
}
Void startPluto(String namespace, String values) {
container("k8s") {
dir('goofy-client/apps/goofy-e2e/deployment-values/pluto') {
withCredentials([usernamePassword(credentialsId: 'jenkins-nexus-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
sh "helm upgrade --install --create-namespace pluto pluto -f ${values} --namespace ${namespace}" + ' --repo https://nexus.ozg-sh.de/repository/ozg-base-apps --username ${USER} --password ${PASSWORD} --wait --wait-for-jobs'
}
}
sh "kubectl rollout status statefulset/pluto-database -n ${namespace}"
}
}
Void startGoofy(String namespace, String values, String imageTag) {
container("k8s") {
dir('goofy-client/apps/goofy-e2e/deployment-values/goofy') {
withCredentials([usernamePassword(credentialsId: 'jenkins-nexus-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
sh "helm upgrade --install --create-namespace goofy goofy -f ${values} --set image.tag=${imageTag} --namespace ${namespace}" + ' --repo https://nexus.ozg-sh.de/repository/ozg-base-apps --username ${USER} --password ${PASSWORD} --wait --wait-for-jobs'
createKeycloakGroups(namespace)
generateKeycloakUserYaml(namespace)
applyKeycloakUser(namespace)
}
Void runTests(String stageName, String reportFolder) {
container("cypress") {
def configFile = generateCypressConfig(stageName, reportFolder)
dir("goofy-client") {
sh "npm run cypress:version"
return sh (script: "npm run cypress:ci-run --CONFIG_FILE=${configFile} --REPORT_FOLDER=${reportFolder}", returnStatus: true)
}
}
}
Void shutdownEnvironment(String namespace) {
container("k8s") {
sh "helm uninstall goofy --namespace ${namespace} --wait"
sh "helm uninstall pluto --namespace ${namespace} --wait"
sh "kubectl delete namespace ${namespace}"
}
}
String makeUrlConform(String input) {
return input.replaceAll(/[^a-zA-Z0-9]+/, "").toLowerCase()
def branchName = makeUrlConform(env.BRANCH_NAME)
def stageName = makeUrlConform(stage)
def e2eUserFiles = sh (script: 'ls goofy-client/apps/goofy-e2e/src/fixtures/user', returnStdout: true)
def newUserYaml = readYaml file: "goofy-client/apps/goofy-e2e/deployment-values/goofy/user/user.yaml"
def userJson = readJSON file: 'goofy-client/apps/goofy-e2e/src/fixtures/user/'+user
newUserYaml.metadata.name = namespace + "-" + userJson.name
newUserYaml.metadata.labels.realm = namespace
newUserYaml.spec.realmSelector.matchLabels.realm = namespace
newUserYaml.spec.user.username = userJson.name
newUserYaml.spec.user.credentials = [[type: 'password', value: userJson.password]]
if(userJson.firstName) {
newUserYaml.spec.user.firstName = userJson.firstName
}
if(userJson.lastName) {
newUserYaml.spec.user.lastName = userJson.lastName
}
if(userJson.realmRoles) {
newUserYaml.spec.user.realmRoles += userJson.realmRoles
}
if(userJson.groups) {
newUserYaml.spec.user.groups = userJson.groups
}
dir (namespace) {
writeYaml file: userJson.name+".yaml", data: newUserYaml
}
}
}
Void createKeycloakGroups(String realm) {
def groupFiles = sh (script: 'ls goofy-client/apps/goofy-e2e/src/fixtures/group', returnStdout: true)
def groupJson = sh (script: "cat goofy-client/apps/goofy-e2e/src/fixtures/group/${group}", returnStdout: true)
sh """curl -X POST 'https://sso.dev.ozg-sh.de/auth/admin/realms/${realm}/groups' \
-H 'Content-Type: application/json' \
-H 'Authorization: bearer ${getKeycloakAccessToken()}' \
--data-raw '${groupJson}'
"""
}
}
Void applyKeycloakUser(String namespace) {
dir(namespace){
def kcUserFiles = sh (script: "ls", returnStdout: true)
kcUserFiles.split("\\n").each { user ->
sh "kubectl apply -f ${user}"
}
}
}
Void removeKeycloakUser(String namespace) {
dir(namespace){
def kcUserFiles = sh (script: "ls", returnStdout: true)
kcUserFiles.split("\\n").each { user ->
sh "kubectl delete -f ${user}"
}
}
}
String generateCypressConfig(String stage, String testFolder) {
def namespace = generateNamespaceName(stage)
def configName = "cypress-ci-"+testFolder+".json"
dir('goofy-client/apps/goofy-e2e/'){
def config = readJSON file: 'cypress-ci.json'
config.baseUrl = "https://${makeUrlConform(env.BRANCH_NAME)}${makeUrlConform(stage)}.dev.ozg-sh.de" as String
config.env.dbUrl = "mongodb+srv://pluto-database-user:XnHhfznNWg65NNd@pluto-database-svc.${namespace}.svc.cluster.local/admin?ssl=false" as String
config.env.keycloakRealm = namespace as String
config.env.keycloakClient = namespace + "-goofy" as String
config.env.sabineUuid = getKeycloakUuid(namespace, "sabine") as String
config.integrationFolder = "./src/integration/${testFolder}" as String
config.videosFolder = "./reports/${testFolder}/videos" as String
config.screenshotsFolder = "./reports/${testFolder}/screenshots" as String
config.reporterOptions.reportDir = "./reports/${testFolder}/mochawesome-report" as String
writeJSON file: configName, json: config
return configName
}
String getKeycloakUuid(realm, userName) {
def shScript = """curl -H 'Content-Type: application/json' \
-H 'Authorization: bearer ${getKeycloakAccessToken()}' \
'https://sso.dev.ozg-sh.de/auth/admin/realms/${realm}/users'
"""
def users = readJSON text: sh(script: shScript, returnStdout: true)
for(user in users) {
}
}
}
String getKeycloakAccessToken() {
withCredentials([usernamePassword(credentialsId: 'keycloak-login', usernameVariable: 'USER', passwordVariable: 'PASSWORD')]) {
def token = readJSON text: sh (script: 'curl -d "client_id=admin-cli" -d "username=$USER" -d "password=$PASSWORD" -d "grant_type=password" "https://sso.dev.ozg-sh.de/auth/realms/master/protocol/openid-connect/token"', returnStdout: true)
return token.access_token