{"id":14155258,"url":"https://github.com/cloudogu/ces-build-lib","last_synced_at":"2025-04-05T07:03:31.570Z","repository":{"id":22425985,"uuid":"82942784","full_name":"cloudogu/ces-build-lib","owner":"cloudogu","description":"Jenkins pipeline shared library adding features for Maven, Gradle, Docker, SonarQube, Git and others","archived":false,"fork":false,"pushed_at":"2024-10-14T11:55:55.000Z","size":1279,"stargazers_count":75,"open_issues_count":15,"forks_count":49,"subscribers_count":13,"default_branch":"develop","last_synced_at":"2024-10-20T12:57:11.038Z","etag":null,"topics":["ces","docker","git","gradle","java","jenkins","jenkins-pipeline","maven","sonarqube"],"latest_commit_sha":null,"homepage":"","language":"Groovy","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudogu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-23T15:46:25.000Z","updated_at":"2024-10-15T16:14:13.000Z","dependencies_parsed_at":"2024-10-25T11:05:07.789Z","dependency_job_id":"409cdbab-ae0f-4c99-ba16-b0e06a55dcae","html_url":"https://github.com/cloudogu/ces-build-lib","commit_stats":{"total_commits":497,"total_committers":29,"mean_commits":"17.137931034482758","dds":0.579476861167002,"last_synced_commit":"ef108796f6e167dfe1d3abaad74810b6be7dd714"},"previous_names":[],"tags_count":111,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fces-build-lib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fces-build-lib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fces-build-lib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudogu%2Fces-build-lib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudogu","download_url":"https://codeload.github.com/cloudogu/ces-build-lib/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299831,"owners_count":20916190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ces","docker","git","gradle","java","jenkins","jenkins-pipeline","maven","sonarqube"],"created_at":"2024-08-17T08:02:35.919Z","updated_at":"2025-04-05T07:03:31.554Z","avatar_url":"https://github.com/cloudogu.png","language":"Groovy","readme":"# ces-build-lib\n\nJenkins Pipeline Shared library, that contains additional features for Git, Maven, etc. in an object-oriented manner as well as some additional pipeline steps.\n\n# Table of contents\n\u003c!-- Update with `doctoc --notitle README.md`. See https://github.com/thlorenz/doctoc --\u003e\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Usage](#usage)\n- [Syntax completion](#syntax-completion)\n- [Maven](#maven)\n  - [Maven from local Jenkins tool](#maven-from-local-jenkins-tool)\n  - [Maven Wrapper](#maven-wrapper)\n    - [With local JDK tool](#with-local-jdk-tool)\n    - [With the JDK provided by the build agent](#with-the-jdk-provided-by-the-build-agent)\n  - [Maven in Docker](#maven-in-docker)\n    - [Plain Maven In Docker](#plain-maven-in-docker)\n    - [Maven Wrapper In Docker](#maven-wrapper-in-docker)\n    - [Advanced Maven in Docker features](#advanced-maven-in-docker-features)\n      - [Maven starts new containers](#maven-starts-new-containers)\n      - [Local repo](#local-repo)\n        - [Maven in Docker](#maven-in-docker-1)\n        - [Set image and credentials](#set-image-and-credentials)\n        - [Maven without Docker](#maven-without-docker)\n      - [Lazy evaluation / execute more steps inside container](#lazy-evaluation--execute-more-steps-inside-container)\n  - [Mirrors](#mirrors)\n  - [Repository Credentials](#repository-credentials)\n  - [Deploying to Nexus repository](#deploying-to-nexus-repository)\n    - [Deploying artifacts](#deploying-artifacts)\n      - [Simple deployment](#simple-deployment)\n      - [Signing artifacts (e.g. Maven Central)](#signing-artifacts-eg-maven-central)\n      - [Deploying with staging (e.g. Maven Central)](#deploying-with-staging-eg-maven-central)\n    - [Deploying sites](#deploying-sites)\n    - [Passing additional arguments](#passing-additional-arguments)\n  - [Maven Utilities](#maven-utilities)\n- [Gradle](#gradle)\n  - [Gradle Wrapper in Docker](#gradle-wrapper-in-docker)\n- [Git](#git)\n  - [Credentials](#credentials)\n  - [Git Utilities](#git-utilities)\n    - [Read Only](#read-only)\n    - [Changes to local repository](#changes-to-local-repository)\n    - [Changes to remote repository](#changes-to-remote-repository)\n- [Docker](#docker)\n  - [`Docker` methods provided by the docker plugin](#docker-methods-provided-by-the-docker-plugin)\n  - [Additional features provided by the `Docker` class](#additional-features-provided-by-the-docker-class)\n  - [`Docker.Image` methods provided by the docker plugin](#dockerimage-methods-provided-by-the-docker-plugin)\n  - [Additional features provided by the `Docker.Image` class](#additional-features-provided-by-the-dockerimage-class)\n- [Dockerfile](#dockerfile)\n- [SonarQube](#sonarqube)\n  - [Constructors](#constructors)\n  - [A complete example](#a-complete-example)\n  - [Branches](#branches)\n  - [SonarCloud](#sonarcloud)\n  - [Pull Requests in SonarQube](#pull-requests-in-sonarqube)\n- [Changelog](#changelog)\n  - [changelogFileName](#changelogfilename)\n- [GitHub](#github)\n- [GitFlow](#gitflow)\n- [SCM-Manager](#scm-manager)\n  - [Pull Requests](#pull-requests)\n- [HttpClient](#httpclient)\n- [K3d](#k3d)\n- [DoguRegistry](#doguregistry)\n- [Bats](#bats)\n- [Makefile](#makefile)\n- [Markdown](#markdown)\n    - [DockerLint (Deprecated)](#dockerlint-deprecated)\n    - [ShellCheck](#shellcheck)\n- [Trivy](#trivy)\n- [Steps](#steps)\n  - [mailIfStatusChanged](#mailifstatuschanged)\n  - [isPullRequest](#ispullrequest)\n  - [findEmailRecipients](#findemailrecipients)\n  - [findHostName](#findhostname)\n  - [isBuildSuccessful](#isbuildsuccessful)\n  - [checkChangelog](#checkchangelog)\n  - [checkReleaseNotes](#checkreleasenotes)\n  - [findVulnerabilitiesWithTrivy](#findvulnerabilitieswithtrivy)\n    - [Simple examples](#simple-examples)\n    - [Ignore / allowlist](#ignore--allowlist)\n- [Examples](#examples)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# Usage\n\n* Install [Pipeline: GitHub Groovy Libraries](https://wiki.jenkins.io/display/JENKINS/Pipeline+GitHub+Library+Plugin)\n* Use the Library in any Jenkinsfile like so\n```\n@Library('github.com/cloudogu/ces-build-lib@2.2.1')\nimport com.cloudogu.ces.cesbuildlib.*\n```\n* Best practice: Use a defined version (e.g. a git commit hash or a git tag, such as `6cd41e0` or `1.67.0` in the example above) and not a branch such as `develop`. Otherwise, your build might change when the there is a new commit on the branch. Using branches is like using snapshots!\n* When build executors are docker containers and you intend to use their Docker host in the Pipeline: Please see [#8](https://github.com/cloudogu/ces-build-lib/issues/8#issuecomment-353584252).\n\n# Syntax completion\n\nYou can get syntax completion in your `Jenkinsfile` when using the ces-build-lib, by adding it as dependency to your project. \n\nYou can get the source.jar from JitPack.\n\nWith Maven this can be done like so:\n\n* Define the JitPack repository:\n    ```XML\n    \u003crepositories\u003e\n        \u003crepository\u003e\n            \u003cid\u003ejitpack.io\u003c/id\u003e\n            \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n        \u003c/repository\u003e\n    \u003c/repositories\u003e\n    ```\n* And the ces-build-lib dependency:\n    ```XML\n    \u003cdependency\u003e\n        \u003c!-- Shared Library used in Jenkins. Including this in maven provides code completion in Jenkinsfile. --\u003e\n        \u003cgroupId\u003ecom.github.cloudogu\u003c/groupId\u003e\n        \u003cartifactId\u003eces-build-lib\u003c/artifactId\u003e\n        \u003c!-- Keep this version in sync with the one used in Jenkinsfile --\u003e\n        \u003cversion\u003e888733b\u003c/version\u003e\n        \u003c!-- Don't ship this dependency with the app --\u003e\n        \u003coptional\u003etrue\u003c/optional\u003e\n        \u003c!-- Don't inherit this dependency! --\u003e\n        \u003cscope\u003eprovided\u003c/scope\u003e\n    \u003c/dependency\u003e\n    ```\nOr you can download the file (and sources) manually and add them to your IDE. For example:\n\n* `https://jitpack.io/com/github/cloudogu/ces-build-lib/9fa7ac4/ces-build-lib-9fa7ac4.jar`\n* `https://jitpack.io/com/github/cloudogu/ces-build-lib/9fa7ac4/ces-build-lib-9fa7ac4-sources.jar`\n\nCurrent version is [![](https://jitpack.io/v/cloudogu/ces-build-lib.svg)](https://jitpack.io/#cloudogu/ces-build-lib).\u003cbr/\u003e \nFor further details and options refer to the [JitPack website](https://jitpack.io/#cloudogu/ces-build-lib).\n\nThis is confirmed to work with IntelliJ IDEA.\n\n# Maven\n\n## Maven from local Jenkins tool\n\nRun maven from a local tool installation on Jenkins.\n\nSee [MavenLocal](src/com/cloudogu/ces/cesbuildlib/MavenLocal.groovy)\n\n```\ndef mvnHome = tool 'M3'\ndef javaHome = tool 'OpenJDK-8'\nMaven mvn = new MavenLocal(this, mvnHome, javaHome)\n\nstage('Build') {\n    mvn 'clean install'\n}\n```\n\n## Maven Wrapper\n\nRun maven using a [Maven Wrapper](https://github.com/takari/maven-wrapper) from the local repository.\n\n### With local JDK tool\n\nSimilar to `MavenLocal` you can use the Maven Wrapper with a JDK from a local tool installation on Jenkins:\n\n```\ndef javaHome = tool 'OpenJDK-8'\nMaven mvn = new MavenWrapper(this, javaHome)\n\nstage('Build') {\n    mvn 'clean install'\n}\n```\n\n### With the JDK provided by the build agent\n\nIt is also possible to not specify a JDK tool and use the Java Runtime on the Build agent's `PATH`. However, \nexperience tells us that this is absolutely non-deterministic and will result in unpredictable behavior.  \nSo: Better set an explicit Java tool to be used or use `MavenWrapperInDocker.`\n\n```\nMaven mvn = new MavenWrapper(this)\n\nstage('Build') {\n    mvn 'clean install'\n}\n```\n\n## Maven in Docker\n\nRun maven in a docker container. This can be helpful, when\n\n* constant ports are bound during the build that cause port conflicts in concurrent builds. For example, when running \n  integration tests, unit tests that use infrastructure that binds to ports or\n* one maven repo per builds is required For example when concurrent builds of multi module project install the same \n  snapshot versions.\n  \n### Plain Maven In Docker\n\nThe builds are run inside the official maven containers from [Dockerhub](https://hub.docker.com/_/maven/)\n\nSee [MavenInDocker](src/com/cloudogu/ces/cesbuildlib/MavenInDocker.groovy)\n\n```\nMaven mvn = new MavenInDocker(this, \"3.5.0-jdk-8\")\n\nstage('Build') {\n    mvn 'clean install'\n}\n```\n\n### Maven Wrapper In Docker\n\nIt's also possible to use the MavenWrapper in a Docker Container. Here, the Docker container is responsible for \nproviding the JDK.\n\nSee [MavenWrapperInDocker](src/com/cloudogu/ces/cesbuildlib/MavenWrapperInDocker.groovy)\n\n```\nMaven mvn = MavenWrapperInDocker(this, 'adoptopenjdk/openjdk11:jdk-11.0.10_9-alpine')\n\nstage('Build') {\n    mvn 'clean install'\n}\n```\n\nSince Oracle's announcement of shorter free JDK support, plenty of JDK images have appeared on public container image \nregistries, where `adoptopenjdk` is just one option. The choice is yours. \n\n### Advanced Maven in Docker features\n\nThe following features apply to plain Maven as well as Maven Wrapper in Docker.\n\n#### Maven starts new containers\n\nIf you run Docker from your maven build, because you use the \n[docker-maven-plugin](https://github.com/fabric8io/docker-maven-plugin) for example, you can connect the docker socket \nthrough to your docker in maven like so:\n\n```\nstage('Unit Test') {\n    // The UI module build runs inside a docker container, so pass the docker host to the maven container\n    mvn.enableDockerHost = true\n\n    mvn docker:start \n\n    // Don't expose docker host more than necessary\n    mvn.enableDockerHost = false\n}\n```\nThere are some security-related concerns about this. See [Docker](#docker).\n\n#### Local repo\n\n##### Maven in Docker\nIf you would like to use Jenkin's local maven repo (or more accurate the one of the build executor, typically at `/home/jenkins/.m2`) \ninstead of a maven repo per job (within each workspace), you can use the following options:\n\n```\nMaven mvn = new MavenInDocker(this, \"3.5.0-jdk-8\")\nmvn.useLocalRepoFromJenkins = true\n```\n\nThis speed speeds up the first build and uses less memory.\nHowever, concurrent builds of multi module projects building the same version (e.g. a SNAPSHOT), might overwrite their dependencies, causing non-deterministic build failures.\n\n##### Set image and credentials\nIt is possible to set credentials for a registry login by setting a credentialsId and custom image with registry prefix.\n```groovy\nMaven mvn = new MavenInDocker(this, \"3.5.0-jdk-8\") // uses image: maven:3.5.0-jdk-8 from DockerHub\nMaven mvn1 = new MavenInDocker(this, \"mirror.gcr.io/maven:latest\") // uses image: maven:latest from Google\nMaven mvn2 = new MavenInDocker(this, \"3.5.0-jdk-8\" , credentialsId) // loads the username and password credentials from jenkins\n```\n\n##### Maven without Docker\n\nThe default is the default maven behavior `/home/jenkins/.m2` is used.\nIf you want to use a separate maven repo per Workspace (e.g. to avoid concurrent builds overwriting \ndependencies of multi module projects building the same version (e.g. a SNAPSHOT) the following will work:\n\n```groovy\nmvn.additionalArgs += \" -Dmaven.repo.local=${env.WORKSPACE}/.m2\"\n```\n\n#### Lazy evaluation / execute more steps inside container\n \nIf you need to execute more steps inside the maven container you can pass a closure to your maven instance that is \nlazily evaluated within the container. The String value returned are the maven arguments. \n\n```\nMaven mvn = new MavenInDocker(this, \"3.5.0-jdk-8\"),\necho \"Outside Maven Container! ${new Docker(this).findIp()}\"\nmvn {\n    echo \"Insinde Maven Container! ${new Docker(this).findIp()}\"\n    'clean package -DskipTests'\n}\n```\n\n## Mirrors\n\nYou can define maven mirrors as follows:\n\n```groovy\nMaven.useMirrors([name: 'maven-proxy', mirrorOf: 'central', url: 'https://maven.example.org'],\n                 [name: 'google-maven', mirrorOf: 'central', url: 'https://maven-central.storage.googleapis.com/maven2/'],\n)\n````\n\n## Repository Credentials\n\nIf you specified one or more `\u003crepository\u003e` in your `pom.xml` that requires authentication, you can pass these \ncredentials to your ces-build-lib `Maven` instance like so:\n\n```groovy\nmvn.useRepositoryCredentials([id: 'ces', credentialsId: 'nexusSystemUserCredential'],\n                             [id: 'another', credentialsId: 'nexusSystemUserCredential'])\n```\n\nNote that the `id` must match the one specified in your `pom.xml` and the credentials ID must belong to a username and\n password credential defined in Jenkins.\n\n## Deploying to Nexus repository \n\n### Deploying artifacts\n\nces-build-lib makes deploying to nexus repositories easy, even when it includes signing of the artifacts and usage of \nthe nexus staging plugin (as necessary for Maven Central or other Nexus repository pro instances).\n \n#### Simple deployment\n\nThe most simple use case is to deploy to a nexus repo (*not* Maven Central):\n \n* Just set the repository using `Maven.useRepositoryCredentials()` by passing a nexus username and password/access token\n  as jenkins username and password credential and\n  * either a repository ID that matches a `\u003cdistributionManagement\u003e\u003crepository\u003e` (or `\u003csnapshotRepository\u003e`, examples \n    bellow) defined in your `pom.xml` (then, no `url` or `type` parameters are needed)    \n    (`distributionManagement` \u003e `snapshotRepository` or `repository` (depending on the `version`) \u003e `id`)\n  * or a repository ID (you can choose) and the URL.  \n    In this case you can alos specifiy a `type: 'Nexus2'` (defaults to Nexus3) - as the base-URLs differ.\n    **This approach is deprecated and might be removed from ces-build-lib in the future.**\n* Call `Maven.deployToNexusRepository()`. And that is it. \n\nSimple Example: \n```\n# \u003cdistributionManagement\u003e in pom.xml (preferred)\nmvn.useRepositoryCredentials([id: 'ces', credentialsId: 'nexusSystemUserCredential'])\n# Alternative: Distribution management via Jenkins (deprecated)\nmvn.useRepositoryCredentials([id: 'ces', url: 'https://ecosystem.cloudogu.com/nexus', credentialsId: 'nexusSystemUserCredential', type: 'Nexus2'])\n\n# Deploy\nmvn.deployToNexusRepository()    \n```\n\nNote that if the pom.xml's version contains `-SNAPSHOT`, the artifacts are automatically deployed to the \nsnapshot repository ([e.g. on oss.sonatype.org](https://oss.sonatype.org/content/repositories/snapshots/)). Otherwise, \nthe artifacts are deployed to the release repository ([e.g. on oss.sonatype.org](https://oss.sonatype.org/content/repositories/releases/)).\n\n#### Signing artifacts (e.g. Maven Central)\n\nIf you want to sign the artifacts before deploying, just set the credentials for signing before deploying, using \n`Maven.setSignatureCredentials()` passing the secret key as ASC file (as jenkins secret file credential) and the \npassphrase (as jenkins secret text credential).\nAn ASC file can be exported via  `gpg --export-secret-keys -a ABCDEFGH \u003e secretkey.asc`.\nSee [Working with PGP Signatures](http://central.sonatype.org/pages/working-with-pgp-signatures.html)\n\n#### Deploying with staging (e.g. Maven Central)\n\nAnother option is to use the nexus-staging-maven-plugin instead of the default maven-deploy-plugin.\nThis is useful if you deploy to a Nexus repository pro, such as Maven Central. \n\nJust use the `Maven.deployToNexusRepositoryWithStaging()` instead of `Maven.deployToNexusRepository()`.\n\nWhen deploying to Maven Central, make sure that your `pom.xml` adheres to the requirements by Maven Central, as stated\n[here](http://central.sonatype.org/pages/requirements.html).\n\nNote that as of nexus-staging-maven-plugin version 1.6.8, it \n[does seem to read the distribution repositories from pom.xml only](https://issues.sonatype.org/browse/NEXUS-15464).\n\nThat is, you need to specify them in your pom.xml, they cannot be passed by the ces-build-lib. So for example for maven \ncentral you need to add the following:\n\n```xml\n\u003cdistributionManagement\u003e\n    \u003csnapshotRepository\u003e\n        \u003cid\u003eossrh\u003c/id\u003e\n        \u003curl\u003ehttps://oss.sonatype.org/content/repositories/snapshots\u003c/url\u003e\n    \u003c/snapshotRepository\u003e\n    \u003crepository\u003e\n        \u003cid\u003eossrh\u003c/id\u003e\n        \u003curl\u003ehttps://oss.sonatype.org/service/local/staging/deploy/maven2/\u003c/url\u003e\n    \u003c/repository\u003e\n\u003c/distributionManagement\u003e\n```\n\nIn addition you either have to pass an `url` to `useRepositoryCredentials()` or specify the nexus-staging-maven plugin in your pom.xml:\n\n```xml\n  \u003cplugin\u003e\n    \u003cgroupId\u003eorg.sonatype.plugins\u003c/groupId\u003e\n    \u003cartifactId\u003enexus-staging-maven-plugin\u003c/artifactId\u003e\n    \u003c!-- ... --\u003e\n    \u003cconfiguration\u003e\n      \u003cserverId\u003eossrh\u003c/serverId\u003e\n      \u003cnexusUrl\u003ehttps://oss.sonatype.org/\u003c/nexusUrl\u003e\n    \u003c/configuration\u003e\n  \u003c/plugin\u003e\n```\n          \nEither way, the repository ID (here: `ossrh`) and the base nexus URL (here: `https://oss.sonatype.org`) in \n`distributionManagement` and `nexus-staging-maven plugin` must conform to each other.\n\nSumming up, here is an example for deploying to Maven Central:\n\n```\n// url is optional, if described in nexus-staging-maven-plugin in pom.xml \nmvn.useRepositoryCredentials([id: 'ossrh', url: 'https://oss.sonatype.org', credentialsId: 'mavenCentral-UsernameAndAcccessTokenCredential', type: 'Nexus2'])\nmvn.setSignatureCredentials('mavenCentral-secretKey-asc-file','mavenCentral-secretKey-Passphrase')\nmvn.deployToNexusRepositoryWithStaging()            \n```\n\nNote that the staging of releases might well take 10 minutes. After that, the artifacts are in the \n[release repository](https://oss.sonatype.org/content/repositories/releases/), which is *later* (feels like nightly) \nsynced to Maven Central.  \n\nFor an example see [cloudogu/command-bus](https://github.com/cloudogu/command-bus).\n\n### Deploying sites\n\nSimilar to deploying artifacts as described above, we can also easily deploy a [Maven site](https://maven.apache.org/guides/mini/guide-site.html)\nto a \"raw\" maven repository.  \n\nNote that the site plugin [does not provide options to specify the target repository via the command line](http://maven.apache.org/plugins/maven-site-plugin/deploy-mojo.html).\nThat is, it has to be configured in the pom.xml like so:\n\n```xml\n\u003cdistributionManagement\u003e\n    \u003csite\u003e\n        \u003cid\u003eces\u003c/id\u003e\n        \u003cname\u003esite repository cloudogu ecosystem\u003c/name\u003e\n        \u003curl\u003edav:https://your.domain/nexus/repository/Site-repo/${project.groupId}/${project.artifactId}/${project.version}/\u003c/url\u003e\n    \u003c/site\u003e\n\u003c/distributionManagement\u003e\n```\nWhere `Site-repo` is the name of the raw repository that must exist in Nexus to succeed.\n\nThen, you can deploy the site as follows:\n\n```groovy\nmvn.useRepositoryCredentials([id: 'ces', credentialsId: 'nexusSystemUserCredential'])\nmvn.deploySiteToNexus()\n```\n\nWhere\n \n* the `id` parameter must match the one specified in the `pom.xml`(`ces` in the example above), \n* the nexus username and password/access token are passed as jenkins username and password credential \n  (`nexusSystemUserCredential`).\n* there is no difference between Nexus 2 and Nexus 3 regarding site deployments.\n\nFor an example see [cloudogu/continuous-delivery-slides-example](https://github.com/cloudogu/continuous-delivery-slides-example/)\n\n### Passing additional arguments\n\nAnother option for `deployToNexusRepositoryWithStaging()` and `deployToNexusRepository()` is to pass additional maven \narguments to the deployment like so: `mvn.deployToNexusRepositoryWithStaging('-X')` (enables debug output).\n\n## Maven Utilities\n\nAvailable from both local Maven and Maven in Docker.\n\n* `mvn.getVersion()`\n* `mvn.getArtifactId()`\n* `mvn.getGroupId()`\n* `mvn.getMavenProperty('project.build.sourceEncoding')`\n\nSee [Maven](src/com/cloudogu/ces/cesbuildlib/MavenInDocker.groovy)\n\n# Gradle\n\n## Gradle Wrapper in Docker\n\nIt's also possible to use a GradleWrapper in a Docker Container. Here, the Docker container is responsible for\nproviding the JDK.\n\nSee [GradleWrapperInDocker](src/com/cloudogu/ces/cesbuildlib/GradleWrapperInDocker.groovy)\n\nExample:\n```groovy\nString gradleDockerImage = 'openjdk:11.0.10-jdk'\nGradle gradlew = new GradleWrapperInDocker(this, gradleDockerImage)\n\nstage('Build') {\n    gradlew \"clean build\"\n}\n```\n\nSince Oracle's announcement of shorter free JDK support, plenty of JDK images have appeared on public container image\nregistries, where `adoptopenjdk` is just one option. The choice is yours.\n\nSee [Maven in Docker](#set-image-and-credentials) for passing credentials to the registry.\n\n# Git\n\nAn extension to the `git` step, that provides an API for some commonly used git commands and utilities.\nMostly, this is a convenient wrapper around using the `sh 'git ...'` calls.\n\nExample: \n\n```groovy\nGit git = new Git(this)\n\nstage('Checkout') {\n  git 'https://your.repo'\n  /* Don't remove folders starting in \".\" like .m2 (maven), .npm, .cache, .local (bower), etc. */\n  git.clean('\".*/\"')\n}\n```\n\n## Credentials\n\nYou can optionally pass `usernamePassword` (i.e. a String containing the ID that refers to the \n[Jenkins credentials](https://jenkins.io/doc/book/using/using-credentials/)) to `Git` during construction. \nThese are then used for cloning and pushing.\n\nNote that the username and passwort are processed by a shell. Special characters in username or password might cause \nerrors like `Unterminated quoted string`. So it's best to use a long password that only contains letters and numbers \nfor now.\n\n```\nGit annonymousGit = new Git(this)\nGit gitWithCreds = new Git(this, 'ourCredentials')\n\n\nannonymousGit 'https://your.repo'\ngitWithCreds 'https://your.repo' // Implicitly passed credentials\n```\n\n## Git Utilities\n\n### Read Only\n\n* `git.clean()` - Removes all untracked and unstaged files.\n* `git.clean('\".*/\"')` - Removes all untracked and unstaged files, except folders starting in \".\" like .m2 (maven), \n  .npm, .cache, .local (bower), etc.\n* `git.branchName` - e.g. `feature/xyz/abc`\n* `git.simpleBranchName` - e.g. `abc`\n* `git.commitAuthorComplete` -  e.g. `User Name \u003cuser.name@doma.in\u003e`\n* `git.commitAuthorEmail` -  e.g. `user.name@doma.in`\n* `git.commitAuthorName` -  e.g. `User Name`\n* `git.commitMessage` -  Last commit message e.g. `Implements new functionality...` \n* `git.commitHash` -  e.g. `fb1c8820df462272011bca5fddbe6933e91d69ed`\n* `git.commitHashShort` -  e.g. `fb1c882`\n* `git.areChangesStagedForCommit()` - `true` if changes are staged for commit. If `false`, `git.commit()` will fail. \n* `git.repositoryUrl` -  e.g. `https://github.com/orga/repo.git`\n* `git.gitHubRepositoryName` -  e.g. `orga/repo`\n* Tags - Note that the git plugin might not fetch tags for all builds. Run `sh \"git fetch --tags\"` to make sure.\n    * `git.tag` -  e.g. `1.0.0` or empty if not set\n    * `git.isTag()` - is there a tag on the current commit?\n\n### Changes to local repository\n\nNote that most changing operations offer parameters to specify an author.\nTheses parameters are optional. If not set the author of the last commit will be used as author and committer.\nYou can specify a different committer by setting the following fields:\n\n* `git.committerName = 'the name'` \n* `git.committerEmail = 'an.em@i.l` \n\nIt is recommended to set a different committer, so it's obvious those commits were done by Jenkins in the name of\nthe author. This behaviour is implemented by GitHub for example when committing via the Web UI.\n\n* `git.checkout('branchname')`\n* `git.checkoutOrCreate('branchname')` - Creates new Branch if it does not exist\n* `git.add('.')`\n* `git.commit('message', 'Author', 'Author@mail.server)`\n* `git.commit('message')` - uses default author/committer (see above).\n* `git.setTag('tag', 'message', 'Author', 'Author@mail.server)`\n* `git.setTag('tag', 'message')` - uses default author/committer (see above).\n* `git.fetch()`\n* `git.pull()` - pulls, and in case of merge, uses default author/committer (see above).\n* `git.pull('refspec')` - pulls specific refspec (e.g. `origin master`), and in case of merge, uses the name and email \n   of the last committer as author and committer.\n* `git.pull('refspec', 'Author', 'Author@mail.server)`\n* `git.merge('develop', 'Author', 'Author@mail.server)`\n* `git.merge('develop')` - uses default author/committer (see above).\n* `git.mergeFastForwardOnly('master')`\n\n### Changes to remote repository\n\n* `git.push('origin master')` - pushes origin\n   **Note**: This always prepends `origin` if not present for historical reasonse (see #44). \n   That is, right now it is impossible to push other remotes.  \n   This will change in the next major version of ces-build-lib.  \n   This limitation does not apply to other remote-related operations such as `pull()`, `fetch()` and `pushAndPullOnFailure()`\n   So it's recommended to explicitly mention the origin and not just the refsepc:\n     * Do: `git.push('origin master')`\n     * Don't: `git.push('master')` because this will no longer work in the next major version.\n* `git.pushAndPullOnFailure('refspec')` - pushes and pulls if push failed e.g. because local and remote have diverged, \n   then tries pushing again\n\n# Docker\n\nThe `Docker` class provides the default methods of the global docker variable provided by [docker plugin](https://github.com/jenkinsci/docker-workflow-plugin):\n\n## `Docker` methods provided by the docker plugin\n \n * `withRegistry(url, credentialsId = null, Closure body)`: Specifies a registry URL such as `https://docker.mycorp.com/`, plus an optional credentials ID to connect to it.   \n   Example:\n     ```groovy\n     def dockerImage = docker.build(\"image/name:1.0\", \"folderOfDockfile\")\n     docker.withRegistry(\"https://your.registry\", 'credentialsId') {\n       dockerImage.push()\n     }\n     ```\n * `withServer(uri, credentialsId = null, Closure body)`: Specifies a server URI such as `tcp://swarm.mycorp.com:2376`, plus an optional credentials ID to connect to it.\n * `withTool(toolName, Closure body)`: Specifies the name of a Docker installation to use, if any are defined in Jenkins global configuration. \n    If unspecified, docker is assumed to be in the `$PATH` of the Jenkins agent.\n * `image(id)`: Creates an Image object with a specified name or ID.   \n    Example:\n     ```groovy\n      docker.image('google/cloud-sdk:164.0.0').inside(\"-e HOME=${pwd()}\") {\n           sh \"echo something\"\n        }\n      ```\n     The image returned by the `Docker` class has additional features see bellow.\n * `build(image, args)`: Runs docker build to create and tag the specified image from a Dockerfile in the current directory.\n    Additional args may be added, such as `'-f Dockerfile.other --pull --build-arg http_proxy=http://192.168.1.1:3128 .'`.\n    Like docker build, args must end with the build context.  \n    Example:\n     ```groovy\n     def dockerContainer = docker.build(\"image/name:1.0\", \"folderOfDockfile\").run(\"-e HOME=${pwd()}\")\n     ```\n\n## Additional features provided by the `Docker` class\n\nThe `Docker` class provides additional convenience features:\n\n * `String findIp(container)` returns the IP address for a docker container instance\n * `String findIp()` returns the IP address in the current context: the docker host ip (when outside of a container) or \n    the ip of the container this is running in\n * `String findDockerHostIp()` returns  the IP address of the docker host. Should work both, if running inside or \n    outside a container \n * `String findEnv(container)` returns the environment variables set within the docker container as string\n * `boolean isRunningInsideOfContainer()` return `true` if this step is executed inside a container, otherwise `false`\n * `boolean isRunning(container)` return `true` if the container is in state running, otherwise `false`\n \nExample from Jenkinsfile:\n```groovy\n Docker docker = new Docker(this)\n def dockerContainer = docker.build(\"image/name:1.0\").run()\n waitUntil {\n     sleep(time: 10, unit: 'SECONDS')\n     return docker.isRunning(dockerContainer)\n }\n echo docker.findIp(dockerContainer)\n echo docker.findEnv(dockerContainer)\n```\n\n## `Docker.Image` methods provided by the docker plugin\n\n* `id`: The image name with optional tag (mycorp/myapp, mycorp/myapp:latest) or ID (hexadecimal hash).\n* `inside(String args = '', Closure body) `: Like `withRun` this starts a container for the duration of the body, but\n  all external commands (sh) launched by the body run inside the container rather than on the host. These commands run in\n  the same working directory (normally a Jenkins agent workspace), which means that the Docker server must be on localhost.\n* `pull`: Runs docker pull. Not necessary before `run`, `withRun`, or `inside`.\n* `run(String args = '', String command = \"\")`:  Uses `docker run` to run the image, and returns a Container which you \n  could stop later. Additional args may be added, such as `'-p 8080:8080 --memory-swap=-1'`. Optional command is \n  equivalent to Docker command specified after the `image()`. Records a run fingerprint in the build.\n* `withRun(String args = '', String command = \"\", Closure body)`:  Like `run` but stops the container as soon as its \n   body exits, so you do not need a try-finally block.\n* `tag(String tagName = image().parsedId.tag, boolean force = true)`: Runs docker tag to record a tag of this image \n  (defaulting to the tag it already has). Will rewrite an existing tag if one exists.\n* `push(String tagName = image().parsedId.tag, boolean force = true)`: Pushes an image to the registry after tagging it \n  as with the tag method. For example, you can use `image().push 'latest'` to publish it as the latest version in its \n  repository.\n  \n## Additional features provided by the `Docker.Image` class\n\n* `repoDigests()`: Returns the repo digests, a content addressable unique digest of an image that was pushed \n   to or pulled  from repositories.  \n   If the image was built locally and not pushed, returns an empty list.  \n   If the image was pulled from or pushed to a repo, returns a list containing one item.  \n   If the image was pulled from or pushed to multiple repos, might also contain more than one digest.  \n* `mountJenkinsUser()`: Setting this to `true` provides the user that executes the build within docker container's `/etc/passwd`.\n  This is necessary for some commands such as npm, ansible, git, id, etc. Those might exit with errors withouta user \n  present.\n    \n  Why?  \n  Note that Jenkins starts Docker containers in the pipeline with the -u parameter (e.g. `-u 1042:1043`).\n  That is, the container does not run as root (which is a good thing from a security point of view).\n  However, the userID/UID (e.g. `1042`) and the groupID/GID (e.g. `1043`) will most likely not be present within the\n  container which causes errors in some executables. \n    \n  How?  \n  Setting this will cause the creation of a `passwd` file that is mounted into a container started from this `image()`\n  (triggered by `run()`, `withRun()` and `inside()` methods). This `passwd` file contains the username, UID, GID of the\n  user that executes the build and also sets the current workspace as `HOME` within the docker container.\n   \n* `mountDockerSocket()`: Setting this to `true` mounts the docker socket into the container.  \n   This allows the container to start other containers \"next to\" itself, that is \"sibling\" containers. Note that this is \n   similar but not the same as \"Docker In Docker\".   \n     \n   Note that this will make the docker host socket accessible from within the the container. Use this wisely. [Some people say](https://dzone.com/articles/never-expose-docker-sockets-period),\n   you should not do this at all. On the other hand, the alternative would be to run a real docker host in docker a \n   docker container, aka \"docker in docker\" or \"dind\" (which [is possible](https://blog.docker.com/2013/09/docker-can-now-run-within-docker/).\n   On this, however, [other people say](http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/), you \n   should not do this at all. So lets stick to mounting the socket, which seems to cause less problems.\n   \n   This is also used by [MavenInDocker](src/com/cloudogu/ces/cesbuildlib/MavenInDocker.groovy) \n* `installDockerClient(String version)`: Installs the docker client with the specified version inside the container.\n   If no version parameter is passed, the lib tries to query the server version by calling `docker version`.  \n   This can be called in addition to mountDockerSocket(), when the \"docker\" CLI is required on the PATH.  \n   \n   For available versions see [here](https://download.docker.com/linux/static/stable/x86_64/).\n\nExamples:\n\nDocker Container that uses its own docker client:\n```groovy\nnew Docker(this).image('docker') // contains the docker client binary\n    .mountJenkinsUser()\n    .mountDockerSocket()\n    .inside() {\n        sh 'whoami' // Would fail without mountJenkinsUser = true\n        sh 'id' // Would fail without mountJenkinsUser = true\n        \n        // Start a \"sibling\" container and wait for it to return\n        sh 'docker run hello-world' // Would fail without mountDockerSocket = true \n        \n    }\n```\n\nDocker container that does not have its own docker client\n```groovy\nnew Docker(this).image('kkarczmarczyk/node-yarn:8.0-wheezy')\n    .mountJenkinsUser()\n    .mountDockerSocket()\n    .installDockerClient('17.12.1')\n    .inside() {\n        // Start a \"sibling\" container and wait for it to return\n        sh 'docker run hello-world' // Would fail without mountDockerSocket = true \u0026 installDockerClient()\n    }\n```\n* If you should need to add addition arguments to `docker run` you can do so globally by setting\n`ADDITIONAL_DOCKER_RUN_ARGS` as global properties at `https://your-jenkins/manage/configure#global-properties`.  \nThis can be used to globally fix certain bugs in Jenkins agents or their docker config.\n\n# Dockerfile\n\nThe `Dockerfile` class provides functions to lint Dockerfiles. For example:\n\n```groovy\nstage('Lint') {\n    Dockerfile dockerfile = new Dockerfile(this)\n    dockerfile.lint() // Lint with default configuration\n    dockerfile.lintWithConfig() // Use your own hadolint configuration with a .hadolint.yaml configuration file\n}\n```\n\nThe tool [hadolint](https://github.com/hadolint/hadolint) is used for linting. It has a lot of configuration parameters\nwhich can be set by creating a `.hadolint.yaml` file in your working directory.\nSee https://github.com/hadolint/hadolint#configure\n\n# SonarQube\n\nWhen analyzing code with SonarQube there are a couple of challenges that are solved using ces-build-lib's \n`SonarQube` class:\n\n* Setting the branch name (note that this only works in Jenkins multi-branch pipeline builds, regular pipelines don't have information about branches - see #11)\n* Analysis for Pull Requests\n* Commenting on Pull Requtests\n* Updating commit status in GitHub for Pull Requests\n* Using the SonarQube branch plugin (SonarQube 6.x, developer edition and sonarcloud.io)\n\n## Constructors\n\nIn general, you can analyse with or without the [SonarQube Plugin for Jenkins](https://wiki.jenkins.io/display/JENKINS/SonarQube+plugin):\n\n* `new SonarQube(this, [sonarQubeEnv: 'sonarQubeServerSetupInJenkins'])` requires the SonarQube plugin and the \n  SonarQube server `sonarQubeServerSetupInJenkins` setup up in your Jenkins instance. You can do this here: \n  `https://yourJenkinsInstance/configure`.\n* `new SonarQube(this, [token: 'secretTextCred', sonarHostUrl: 'http://ces/sonar'])` does not require the plugin \n  and uses an access token, stored as secret text credential `secretTextCred` in your Jenkins instance.   \n* `new SonarQube(this, [usernamePassword: 'usrPwCred', sonarHostUrl: 'http://ces/sonar'])` does not require the \n   plugin and uses a SonarQube user account, stored as username with password credential `usrPwCred` in your Jenkins \n   instance.\n\nWith the `SonarQube` instance you can now analyze your code. When using the plugin (i.e. `sonarQubeEnv`) you can also\nwait for the quality gate status, that is computed by SonarQube asynchronously. Note that this does **not** work for `token`\nand `usernamePassword`.\n \n## A complete example\n\n```groovy\nstage('Statical Code Analysis') {\n  def sonarQube = new SonarQube(this, [sonarQubeEnv: 'sonarQubeServerSetupInJenkins'])\n\n  sonarQube.analyzeWith(new MavenInDocker(this, \"3.5.0-jdk-8\"))\n  sonarQube.timeoutInMinutes = 4\n\n  if (!sonarQube.waitForQualityGateWebhookToBeCalled()) {\n    unstable(\"Pipeline unstable due to SonarQube quality gate failure\")\n  }\n}\n```\n\nNote that\n \n* Calling `waitForQualityGateWebhookToBeCalled()` requires a WebHook to be setup in your SonarQube server (globally or \n  per project), that notifies Jenkins (url: `https://yourJenkinsInstance/sonarqube-webhook/`).  \n  See [SonarQube Scanner for Jenkins](https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner+for+Jenkins#AnalyzingwithSonarQubeScannerforJenkins-AnalyzinginaJenkinspipeline). \n* Jenkins will wait for the webhook with a default timeout of 2 minutes, for big projects this might be to short and can be configured with the `timeoutInMinutes` property.\n* Calling `waitForQualityGateWebhookToBeCalled()` will only work when an analysis has been performed in the current job,\n  i.e. `analyzeWith()` has been called and in conjuction with `sonarQubeEnv`.\n* When used in conjunction with [SonarQubeCommunity/sonar-build-breaker](https://github.com/SonarQubeCommunity/sonar-build-breaker),\n  `waitForQualityGateWebhookToBeCalled()` will fail your build, if quality gate is not passed.\n* For now, `SonarQube` can only analyze using `Maven`. Extending this to use the plain SonarQube Runner in future, \n  should be easy, however.\n  \n## Branches\nBy default, the [sonarqube-community-branch-plugin](https://github.com/mc1arke/sonarqube-community-branch-plugin) is required and used.\nThe reason for this is that since SonarQube version \u003e 25 analysis with the legacy logic (creating one project per branch) fails\non pull request because SonarQube requires the target branch (e.g. main) in the same project.\n\nA more convenient alternative is the paid-version-only [Branch Plugin](https://docs.sonarqube.org/display/PLUG/Branch+Plugin).\n\nYou can enable either branch plugins like so:\n\n```groovy\nsonarQube.isUsingBranchPlugin = true\nsonarQube.analyzeWith(mvn)\n```\n\nThe branch plugin is using `master` as integration branch, if you want use a different branch as `master` you have to use the `integrationBranch` parameter e.g.:\n\n```groovy\ndef sonarQube = new SonarQube(this, [sonarQubeEnv: 'sonarQubeServerSetupInJenkins', integrationBranch: 'develop'])\nsonarQube.isUsingBranchPlugin = true\nsonarQube.analyzeWith(mvn)\n```\n\nNote that using the branch plugin **requires a first analysis without branches**.\n\nYou can do this on Jenkins or locally.\n\nOn Jenkins, you can achieve this by setting the following for the first run:\n```groovy\nsonarQube.isIgnoringBranches = true\nsonarQube.analyzeWith(mvn)\n```\nRecommendation: Use Jenkins' replay feature for this. Then commit the `Jenkinsfile` with `isUsingBranchPlugin`.\n\nAn alternative is running the first analysis locally, e.g. with maven\n`mvn clean install sonar:sonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=YOUR-ORG -Dsonar.login=YOUR-TOKEN`\n \n## SonarCloud\n\n[SonarCloud](https://sonarcloud.io) is a public SonarQube instance that has some extra features, such as PullRequest \ndecoration for GitHub, BitBucket, etc.\nces-build-lib encapsulates the setup in `SonarCloud` class.\nIt works just like `SonarQube`, i.e. you can create it using `sonarQubeEnv`, `token`, etc. and it provides the `analyzeWith()` and \n`waitForQualityGateWebhookToBeCalled()` methods.  \nThe only difference: You either have to pass your organization ID using the `sonarOrganization: 'YOUR_ID'` parameter \nduring construction, or configure it under `https://yourJenkinsInstance/configure` as \"Additional analysis properties\" \n(hit the \"Advanced...\" button to get there): `sonar.organization=YOUR_ID`.\n\nExample using SonarCloud:\n \n```groovy\n  def sonarQube = new SonarCloud(this, [sonarQubeEnv: 'sonarcloud.io', sonarOrganization: 'YOUR_ID'])\n\n  sonarQube.analyzeWith(new MavenInDocker(this, \"3.5.0-jdk-8\"))\n\n  if (!sonarQube.waitForQualityGateWebhookToBeCalled()) {\n    unstable(\"Pipeline unstable due to SonarCloud quality gate failure\")\n  }\n```\n\nJust like for ordinary SonarQube, you have to setup a webhook in SonarCloud for `waitForQualityGateWebhookToBeCalled()` to work (see [above](#a-complete-example)).\n\nIf you want SonarCloud to decorate your Pull Requests, you will have to \n\n* GitHub: Install the [SonarCloud Application for GitHub](https://sonarcloud.io/documentation/integrations/github/) into your GitHub organization or account.\n* BitBucket: Install the [SonarCloud add-on for Bitbucket Cloud](https://sonarcloud.io/documentation/integrations/bitbucketcloud/) into your BitBucket team or account.  \n  Note that ces-build-lib supports only Git repos for now. No mercurial/hg, sorry.\n\nSee also [Pull Request analysis](https://sonarcloud.io/documentation/analysis/pull-request/).\n\nNote that SonarCloud uses the Branch Plugin, so the first analysis has to be done differently, as described in [Branches](#branches).\n\n## Pull Requests in SonarQube\n\nAs described above, SonarCloud can annotate PullRequests using the SonarCloud Application for GitHub.\nFor the regular community edition the [community-branch-plugin](https://github.com/mc1arke/sonarqube-community-branch-plugin) is required.\n\n# Changelog\nProvides the functionality to read changes of a specific version in a changelog that is \nbased on the changelog format on https://keepachangelog.com/.\n\nNote: The changelog will automatically be formatted. Characters like `\"`, `'`, `\\` will be removed. \n      A `\\n` will be replaced with `\\\\n`. This is done to make it possible to pass this string to a json \n      struct as a value.\n\nExample: \n\n```groovy\nChangelog changelog = new Changelog(this)\n\nstage('Changelog') {\n  String changes = changelog.getChangesForVersion('v1.0.0')\n  // ...\n}\n```\n## changelogFileName\nYou can optionally pass the path to the changelog file if it is located somewhere else than in the root path or \nif the file name is not `CHANGELOG.md`.\n\nExample: \n\n```groovy\nChangelog changelog = new Changelog(this, 'myNewChangelog.md')\n\nstage('Changelog') {\n  String changes = changelog.getChangesForVersion('v1.0.0')\n  // ...\n}\n```\n\n# GitHub\nProvides the functionality to do changes on a github repository such as creating a new release.\n\nExample: \n\n```groovy\nGit git = new Git(this)\nGitHub github = new GitHub(this, git)\n\nstage('Github') {\n  github.createRelease('v1.1.1', 'Changes for version v1.1.1')\n}\n```\n\n* `github.createRelease(releaseVersion, changes [, productionBranch])` - Creates a release on github. Returns the GitHub Release-ID.\n   * Use the `releaseVersion` (String) as name and tag.\n   * Use the `changes` (String) as body of the release.\n   * Optionally, use `productionBranch` (String) as the name of the production release branch. This defaults to `master`.\n* `github.createReleaseWithChangelog(releaseVersion, changelog [, productionBranch])` - Creates a release on github. Returns the GitHub Release-ID.\n   * Use the `releaseVersion` (String) as name and tag.\n   * Use the `changelog` (Changelog) to extract the changes out of a changelog and add them to the body of the release.\n   * Optionally, use `productionBranch` (String) as the name of the production release branch. This defaults to `master`.\n* `github.addReleaseAsset(releaseId, filePath)`\n  * The `releaseId` (String) is the unique identifier of a release in the github API. Can be obtained as return value of `createReleaseWithChangelog` or `createRelease`.\n  * The `filePath` specifies the path to the file which should be uploaded.\n* `pushPagesBranch('folderToPush', 'commit Message')` - Commits and pushes a folder to the `gh-pages` branch of \n   the current repo. Can be used to conveniently deliver websites. See https://pages.github.com. Note:\n   * Uses the name and email of the last committer as author and committer.\n   * the `gh-pages` branch is temporarily checked out to the `.gh-pages` folder.\n   * Don't forget to create a git object with credentials.\n   * Optional: You can deploy to a sub folder of your GitHub Pages branch using a third parameter\n   * Examples:\n      * [cloudogu/continuous-delivery-slides](https://github.com/cloudogu/continuous-delivery-slides/)\n      * [cloudogu/k8s-security-3-things](https://github.com/cloudogu/k8s-security-3-things)\n   * See also [Cloudogu Blog: Continuous Delivery with reveal.js](https://cloudogu.com/en/blog/continuous-delivery-with-revealjs) \n\n\n# GitFlow\n\nA wrapper class around the Git class to simplify the use of the git flow branching model.\n\nExample: \n\n```groovy\nGit git = new Git(this)\ngit.committerName = 'jenkins'\ngit.committerEmail = 'jenkins@your.org'\nGitFlow gitflow = new GitFlow(this, git)\n\nstage('Gitflow') {\n  if (gitflow.isReleaseBranch()){\n    gitflow.finishRelease(git.getSimpleBranchName())\n  }\n}\n```\n\n* `gitflow.isReleaseBranch()` - Checks if the currently checked out branch is a gitflow release branch.\n* `gitflow.finishRelease(releaseVersion [, productionBranch])` - Finishes a git release by merging into develop and production release branch (default: \"master\").\n   * Use the `releaseVersion` (String) as the name of the new git release.\n   * Optionally, use `productionBranch` (String) as the name of the production release branch. This defaults to `master`.\n   \n# SCM-Manager\n\nProvides the functionality to handle pull requests on a SCMManager repository.\n\nYou need to pass `usernamePassword` (i.e. a String containing the ID that refers to the\n[Jenkins credentials](https://jenkins.io/doc/book/using/using-credentials/)) to `SCMManager` during construction.\nThese are then used for handling the pull requests.\n\n```groovy\nSCMManager scmm = new SCMManager(this, 'ourCredentials')\n```\n\nSet the repository url through the `repositoryUrl` property like so:\n\n```groovy\nSCMManager scmm = new SCMManager(this, 'https://hostname/scm', 'ourCredentials')\n```\n\n## Pull Requests\n\nEach method requires a `repository` parameter, a String containing namespace and name, e.g. `cloudogu/ces-build-lib`.\n\n* `scmm.searchPullRequestIdByTitle(repository, title)` - Returns a pull request ID by title, or empty, if not present.\n    * Use the `repository` (String) as the GitOps repository\n    * Use the `title` (String) as the title of the pull request in question.\n    * This methods requires the `readJSON()` step from the \n      [Pipeline Utility Steps plugin](https://plugins.jenkins.io/pipeline-utility-steps/).\n* `scmm.createPullRequest(repository, source, target, title, description)` - Creates a pull request, or empty, if not present.\n    * Use the `repository` (String) as the GitOps repository\n    * Use the `source` (String) as the source branch of the pull request.\n    * Use the `target` (String) as the target branch of the pull request.\n    * Use the `title` (String) as the title of the pull request.\n    * Use the `description` (String) as the description of the pull request.\n* `scmm.updatePullRequest(repository, pullRequestId, title, description)` - Updates the pull request.\n    * Use the `repository` (String) as the GitOps repository\n    * Use the `pullRequestId` (String) as the ID of the pull request.\n    * Use the `title` (String) as the title of the pull request.\n    * Use the `description` (String) as the description of the pull request.\n* `scmm.createOrUpdatePullRequest(repository, source, target, title, description)` - Creates a pull request if no PR is found or updates the existing one.\n    * Use the `repository` (String) as the GitOps repository\n    * Use the `source` (String) as the source branch of the pull request.\n    * Use the `target` (String) as the target branch of the pull request.\n    * Use the `title` (String) as the title of the pull request.\n    * Use the `description` (String) as the description of the pull request.\n* `scmm.addComment(repository, pullRequestId, comment)` - Adds a comment to a pull request.\n    * Use the `repository` (String) as the GitOps repository\n    * Use the `pullRequestId` (String) as the ID of the pull request.\n    * Use the `comment` (String) as the comment to add to the pull request.\n\nExample:\n\n```groovy\ndef scmm = new SCMManager(this, 'https://your.ecosystem.com/scm', scmManagerCredentials)\n\ndef pullRequestId = scmm.createPullRequest('cloudogu/ces-build-lib', 'feature/abc', 'develop', 'My title', 'My description')\npullRequestId = scmm.searchPullRequestIdByTitle('cloudogu/ces-build-lib', 'My title')\nscmm.updatePullRequest('cloudogu/ces-build-lib', pullRequestId, 'My new title', 'My new description')\nscmm.addComment('cloudogu/ces-build-lib', pullRequestId, 'A comment')\n```\n\n# HttpClient\n\n`HttpClient` provides a simple `curl` frontend for groovy. \n\n* Not surprisingly, it requires `curl` on the jenkins agents.\n* If you need to authenticate, you can create a `HttpClient` with optional credentials ID (`usernamePassword` credentials)\n* `HttpClient` provides `get()`, `put()` and `post()` methods \n* All methods have the same signature, e.g.  \n  `http.get(url, contentType = '', data = '')`\n   * `url` (String) \n   * optional `contentType` (String) - set as acceptHeader in the request \n   * optional `data` (Object) - sent in the body of the request\n* If successful, all methods return the same data structure a map of\n  * `httpCode` - as string containing the http status code\n  * `headers` - a map containing the response headers, e.g. `[ location: 'http://url' ]`\n  * `body` - an optional string containing the body of the response  \n* In case of an error (Connection refused, Could not resolve host, etc.) an exception is thrown which fails the build\n  right away. If you don't want the build to fail, wrap the call in a `try`/`catch` block.\n\nExample:\n\n```groovy\nHttpClient http = new HttpClient(scriptMock, 'myCredentialID')\n\n// Simplest example\necho http.get('http://url')\n\n// POSTing data\ndef dataJson = JsonOutput.toJson([\n    comment: comment\n])\ndef response = http.post('http://url/comments\"', 'application/json', dataJson)\n\nif (response.status == '201' \u0026\u0026 response.content-type == 'application/json') {\n    def json = readJSON text: response.body\n    echo json.count\n}\n```\n\n# K3d\n\n`K3d` provides functions to set up and administer a local k3s cluster in Docker.\n\nExample:\n\n```groovy\nK3d k3d = new K3d(this, env.WORKSPACE, env.PATH)\n\ntry {\n    stage('Set up k3d cluster') {\n        k3d.startK3d()\n    }\n\n    stage('Do something with your cluster') {\n        k3d.kubectl(\"get nodes\")\n    }\n    stage('Apply your Helm chart') {\n        k3d.helm(\"install path/to/your/chart\")\n    }\n\n    stage('build and push development artefact') {\n        String myCurrentArtefactVersion = \"yourTag-1.2.3-dev\"\n        imageName = k3d.buildAndPushToLocalRegistry(\"your/image\", myCurrentArtefactVersion)\n        // your image name may look like this: k3d-citest-123456/your/image:yourTag-1.2.3-dev\n        // the image name can be applied to your cluster as usual, f. i. with k3d.kubectl() with a customized K8s resource \n    }\n\n    stage('configure components'){\n        // add additional components\n        k3d.configureComponents([\"k8s-minio\"             : [\"version\": \"latest\", \"helmRepositoryNamespace\": \"k8s\"],\n                                 \"k8s-loki\"              : [\"version\": \"latest\", \"helmRepositoryNamespace\": \"k8s\"],\n                                 \"k8s-promtail\"          : [\"version\": \"latest\", \"helmRepositoryNamespace\": \"k8s\"],\n                                 \"k8s-blueprint-operator\": null, // null values will delete components from the config\n        ])\n    }\n    \n    stage('execute k8s-ces-setup') {\n        k3d.setup('0.20.0')\n    }\n\n    stage('install resources and wait for them') {\n        imageName = \"registry.cloudogu.com/official/my-dogu-name:1.0.0\"\n        k3d.installDogu(\"my-dogu-name\", imageName, myDoguResourceYamlFile)\n\n        k3d.waitForDeploymentRollout(\"my-dogu-name\", 300, 5)\n    }\n\n    stage('install a dependent dogu by applying a dogu resource') {\n        k3d.applyDoguResource(\"my-dependency\", \"nyNamespace\", \"10.0.0-1\")\n        k3d.waitForDeploymentRollout(\"my-dependency\", 300, 5)\n    }\n\n} catch (Exception ignored) {\n    // in case of a failed build collect dogus, resources and pod logs and archive them as log file on the build.\n    k3d.collectAndArchiveLogs()\n    throw e\n} finally {\n    stage('Remove k3d cluster') {\n        k3d.deleteK3d()\n    }\n}\n```\n\n# DoguRegistry\n\n`DoguRegistry` provides functions to easily push dogus and k8s components to a configured registry.\n\nExample:\n\n```groovy\nDoguRegistry registry = new DoguRegistry(this)\n\n// push dogu\nregistry.pushDogu()\n\n// push k8s component\nregistry.pushK8sYaml(\"pathToMyK8sYaml.yaml\", \"k8s-dogu-operator\", \"mynamespace\", \"0.9.0\")\n```\n\n# Bats\n\n`Bats` provides functions to easily execute existing bats tests for a project. \n\nExample:\n\n```groovy\nDocker docker = new Docker(this)\n\nstage('Bats Tests') {\n    Bats bats = new Bats(this, docker)\n    bats.checkAndExecuteTests()\n}\n```\n\n# Makefile\n\n`Makefile` provides function regarding the `Makefile` from the current directory.\n\nExample:\n\n```groovy\n    Makefile makefile = new Makefile(this)\n    String currentVersion = makefile.getVersion()\n```\n\n# Markdown\n\n`Markdown` provides function regarding the `Markdown Files` from the projects docs directory  \n\n```groovy\n    Markdown markdown = new Markdown(this)\n    markdown.check()\n```\n\n\n`markdown.check` executes the function defined in `Markdown`\nrunning a container with the latest https://github.com/tcort/markdown-link-check image\nand verifies that the links in the defined project directory are alive\n\nAdditionally, the markdown link checker can be used with a specific version (default: stable).\n\n```groovy\n    Markdown markdown = new Markdown(this, \"3.11.0\")\n    markdown.check()\n```\n\n### DockerLint (Deprecated)\n\nUse Dockerfile.lint() instead of lintDockerfile()!\nSee [Dockerfile](#dockerfile)\n\n```groovy\nlintDockerfile() // uses Dockerfile as default; optional parameter\n```\n\nSee [lintDockerFile](vars/lintDockerfile.groovy)\n\n### ShellCheck\n\n```groovy\nshellCheck() // search for all .sh files in folder and runs shellcheck\nshellCheck(fileList) // fileList=\"a.sh b.sh\" execute shellcheck on a custom list\n```\n\nSee [shellCheck](vars/shellCheck.groovy)\n\n# Trivy\n\nScan container images for vulnerabilities with Trivy.\n\n## Create a Trivy object\n\n```groovy\nTrivy trivy = new Trivy(this)\n// With specific Trivy version\nTrivy trivy = new Trivy(this, \"0.57.1\")\n// With specific Trivy image\nTrivy trivy = new Trivy(this, \"0.57.1\", \"images.mycompany.test/trivy\")\n// With explicit Docker registry\nDocker docker = new Docker(this)\ndocker.withRegistry(\"https://my.registry.invalid\", myRegistryCredentialsID)\nTrivy trivy = new Trivy(this, \"0.57.1\", \"aquasec/trivy\", docker)\n```\n\n## Scan image with Trivy\n\nScan an image with Trivy by calling the `scanImage` function.\n\n```groovy\nTrivy trivy = new Trivy(this)\nboolean imageIsSafe = trivy.scanImage(\"ubuntu:24.04\")\nif (!imageIsSafe){\n    echo \"This image has vulnerabilities!\"\n}\n```\n\n### Set the severity level for the scan\n\nYou can set the severity levels of the vulnerabilities Trivy should scan for as a parameter of the scan method:\n\n```groovy\nTrivy trivy = new Trivy(this)\ntrivy.scanImage(\"ubuntu:24.04\", TrivySeverityLevel.ALL)\ntrivy.scanImage(\"ubuntu:24.04\", \"CRITICAL,LOW\")\n```\n\nFor the available pre-defined severity levels see [TrivySeverityLevel.groovy](src/com/cloudogu/ces/cesbuildlib/TrivySeverityLevel.groovy)\n\n### Set the pipeline strategy\n\nTo define how the Jenkins pipeline should behave if vulnerabilities are found, you can set certain strategies:\n- TrivyScanStrategy.IGNORE: Ignore the vulnerabilities and continue\n- TrivyScanStrategy.UNSTABLE: Mark the job as \"unstable\" and continue\n- TrivyScanStrategy.FAIL: Mark the job as failed\n\n```groovy\nTrivy trivy = new Trivy(this)\ntrivy.scanImage(\"ubuntu:24.04\", TrivySeverityLevel.ALL, TrivyScanStrategy.UNSTABLE)\n```\n\n### Set additional Trivy flags\n\nTo set additional Trivy command flags, use the `additionalFlags` parameter:\n\n```groovy\nTrivy trivy = new Trivy(this)\ntrivy.scanImage(\"ubuntu:24.04\", TrivySeverityLevel.ALL, TrivyScanStrategy.UNSTABLE, \"--db-repository public.ecr.aws/aquasecurity/trivy-db\")\n```\n\nNote that the flags `--db-repository public.ecr.aws/aquasecurity/trivy-db --java-db-repository public.ecr.aws/aquasecurity/trivy-java-db`\nare set by default to avoid rate limiting of Trivy database downloads. If you set `additionalFlags` by yourself, you are overwriting\nthese default flags and have to make sure to include them in your set of additional flags, if needed.\n\n### Set the Trivy report file name\n\nIf you want to run multiple image scans in one pipeline, you can set distinct file names for the report files:\n\n```groovy\nTrivy trivy = new Trivy(this)\ntrivy.scanImage(\"ubuntu:20.04\", TrivySeverityLevel.ALL, TrivyScanStrategy.UNSTABLE, \"\", \"trivy/ubuntu20.json\")\ntrivy.scanImage(\"ubuntu:24.04\", TrivySeverityLevel.ALL, TrivyScanStrategy.UNSTABLE, \"\", \"trivy/ubuntu24.json\")\n// Save report by using the same file name (last parameter)\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.HTML, \"UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL\", \"ubuntu20.04report\", \"trivy/ubuntu20.json\")\n```\n\n## Save Trivy report in another file format\n\nAfter calling the `scanImage` function you can save the scan report as JSON, HTML or table files.\n\n```groovy\nTrivy trivy = new Trivy(this)\ntrivy.scanImage(\"ubuntu:24.04\")\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.TABLE)\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.JSON)\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.HTML)\n```\n\nYou may filter the output to show only specific severity levels (default: `\"UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL\"`):\n\n```groovy\nTrivy trivy = new Trivy(this)\ntrivy.scanImage(\"ubuntu:24.04\")\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.TABLE, \"CRITICAL\")\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.JSON, \"UNKNOWN,LOW,MEDIUM\")\n```\n\nYou may also use any other supported [Trivy format](https://trivy.dev/v0.57/docs/references/configuration/cli/trivy_convert/) or a custom template from a file in your workspace.\n\n```groovy\nTrivy trivy = new Trivy(this)\ntrivy.scanImage(\"ubuntu:24.04\")\ntrivy.saveFormattedTrivyReport(\"cosign-vuln\", \"UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL\", \"ubuntu24.04cosign.txt\")\ntrivy.saveFormattedTrivyReport(\"template --template @myTemplateFile.xyz\", \"UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL\", \"ubuntu24.04myTemplate.txt\")\n```\n\n## Scan Dogu image with Trivy\n\nThis section describes how to get a Dogu image from the testing CES instance and scan it with Trivy.\n\n### Get Dogu image from CES instance\n\nMake sure to have a `build` stage in your Dogu test pipeline which builds the Dogu image, e.g. via\nthe `ecoSystem.build(\"/dogu\")` command.\nAfter the build stage you will be able to copy the Dogu image to your local Jenkins worker via\nthe `ecoSystem.copyDoguImageToJenkinsWorker(\"/dogu\")` command.\n\n### Scan Dogu image\n\nThe `scanDogu()` function lets you scan a Dogu image without typing its full name. The method reads the image name\nand version from the dogu.json inside the directory you point it to via its first argument.\nThe default directory is the current directory.\n\n```groovy\n// Preparation\necoSystem.copyDoguImageToJenkinsWorker(\"/dogu\")\nTrivy trivy = new Trivy(this)\n\n// Scan the Dogu image\ntrivy.scanDogu()\n// Explicitly set directory that contains the dogu code (dogu.json)\ntrivy.scanDogu(\"subfolder/test1/jenkins\")\n// Set scan options just like in the scanImage method\ntrivy.scanDogu(\".\", TrivySeverityLevel.ALL, TrivyScanStrategy.UNSTABLE, \"\", \"trivy/mydogu.json\")\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.TABLE)\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.JSON)\ntrivy.saveFormattedTrivyReport(TrivyScanFormat.HTML)\n```\n\n## Ignore / allowlist\n\nIf you want to ignore / allow certain vulnerabilities, please use a `.trivyignore` file.\n\nProvide the file in your repo `/` directory where you run your job, e.g.:\n\n```shell\n.gitignore\nJenkinsfile\n.trivyignore\n```\n\n[Offical documentation](https://trivy.dev/v0.57/docs/configuration/filtering/#by-finding-ids)\n```ignorelang\n# Accept the risk\nCVE-2018-14618\n\n# Accept the risk until 2023-01-01\nCVE-2019-14697 exp:2023-01-01\n\n# No impact in our settings\nCVE-2019-1543\n\n# Ignore misconfigurations\nAVD-DS-0002\n\n# Ignore secrets\ngeneric-unwanted-rule\naws-account-id\n```\n\n# Steps\n\n## mailIfStatusChanged\n\nProvides the functionality of the Jenkins Post-build Action \"E-mail Notification\" known from freestyle projects.\n\n```\ncatchError {\n // Stages and steps\n}\nmailIfStatusChanged('a@b.cd,123@xy.z')\n```\nSee [mailIfStatusChanged](vars/mailIfStatusChanged.groovy)\n\n## isPullRequest\n\nReturns \u003ccode\u003etrue\u003c/code\u003e if the current build is a pull request (when the `CHANGE_ID`environment variable is set) \nTested with GitHub.\n\n```\nstage('SomethingToSkipWhenInPR') {\n    if (!isPullRequest()) {\n      // ...\n    }\n    \n}\n```\n\n## findEmailRecipients\n\nDetermines the email recipients:\nFor branches that are considered unstable (all except for 'master' and 'develop') only the Git author is returned\n(if present).\nOtherwise, the default recipients (passed as parameter) and git author are returned.\n\n```\ncatchError {\n // Stages and steps\n}\nmailIfStatusChanged(findEmailRecipients('a@b.cd,123@xy.z'))\n```\nThe example writes state changes email to 'a@b.cd,123@xy.z' + git author for stable branches and only to git author \nfor unstable branches.\n\n## findHostName\n\nReturns the hostname of the current Jenkins instance. \nFor example, if running on `http(s)://server:port/jenkins`, `server` is returned.\n\n## isBuildSuccessful\n\nReturns true if the build is successful, i.e. not failed or unstable (yet).\n\n## checkChangelog\n\nAutomatically check if your changelog has been updated if a PR is created.\nIf the changelog has not been updated, the build will become unstable.\n\nUsage:\n\n```groovy\nChangelog changelog = new Changelog(this)\ncheckChangelog(changelog)\n```\n\n## checkReleaseNotes\n\nAutomatically check if your release notes have been updated if a PR is created.\nIf the release notes have not been updated, the build will become unstable.\n\nUsage:\n\n```groovy\nReleaseNotes releaseNotes = new ReleaseNotes(this)\ncheckReleaseNotes(releaseNotes)\n```\n\n## findVulnerabilitiesWithTrivy (Deprecated)\n\nThis function is deprecated. Use [Trivy](#trivy) functionality instead.\n\nReturns a list of vulnerabilities or an empty list if there are no vulnerabilities for the given severity.\n\n`findVulnerabilitiesWithTrivy(trivyConfig as Map)`\n\n```groovy\ntrivyConfig = [ \n    imageName: 'alpine:3.17.2', \n    severity: [ 'HIGH, CRITICAL' ], \n    trivyVersion: '0.41.0',\n    additionalFlags: '--ignore-unfixed'\n]\n```\n\nHere the only mandatory field is `imageName`. If no imageName was passed the function returns an empty list.\n\n- **imageName** *(string)*: The name of the image to be scanned\n- **severity** *(list of strings)*: If left blank all severities will be shown. If one or more are specified only these will be shown\n  i.e. if 'HIGH' is passed then only vulnerabilities with the 'HIGH' score are shown\n- **trivyVersion** *(string)*: The version of the trivy image\n- **additionalFlags** *(string)*: Additional flags for trivy, e.g. `--ignore-unfixed`\n\n### Simple examples\n\n```groovy\nnode {\n    stage('Scan Vulns') {\n        def vulns = findVulnerabilitiesWithTrivy(imageName: 'alpine:3.17.2')\n        if (vulns.size() \u003e 0) {\n            archiveArtifacts artifacts: '.trivy/trivyOutput.json'\n            unstable \"Found  ${vulns.size()} vulnerabilities in image. See vulns.json\"\n        }\n    }\n}\n```\n\n\n\nIf there are vulnerabilities the output looks as follows.\n\n```json\n{\n  \"SchemaVersion\": 2,\n  \"ArtifactName\": \"alpine:3.17.2\",\n  \"ArtifactType\": \"container_image\",\n  \"Metadata\": {\n    \"OS\": {\n      \"Family\": \"alpine\",\n      \"Name\": \"3.17.2\"\n    },\n    \"ImageID\": \"sha256:b2aa39c304c27b96c1fef0c06bee651ac9241d49c4fe34381cab8453f9a89c7d\",\n    \"DiffIDs\": [\n      \"sha256:7cd52847ad775a5ddc4b58326cf884beee34544296402c6292ed76474c686d39\"\n    ],\n    \"RepoTags\": [\n      \"alpine:3.17.2\"\n    ],\n    \"RepoDigests\": [\n      \"alpine@sha256:ff6bdca1701f3a8a67e328815ff2346b0e4067d32ec36b7992c1fdc001dc8517\"\n    ],\n    \"ImageConfig\": {\n      \"architecture\": \"amd64\",\n      \"container\": \"4ad3f57821a165b2174de22a9710123f0d35e5884dca772295c6ebe85f74fe57\",\n      \"created\": \"2023-02-11T04:46:42.558343068Z\",\n      \"docker_version\": \"20.10.12\",\n      \"history\": [\n        {\n          \"created\": \"2023-02-11T04:46:42.449083344Z\",\n          \"created_by\": \"/bin/sh -c #(nop) ADD file:40887ab7c06977737e63c215c9bd297c0c74de8d12d16ebdf1c3d40ac392f62d in / \"\n        },\n        {\n          \"created\": \"2023-02-11T04:46:42.558343068Z\",\n          \"created_by\": \"/bin/sh -c #(nop)  CMD [\\\"/bin/sh\\\"]\",\n          \"empty_layer\": true\n        }\n      ],\n      \"os\": \"linux\",\n      \"rootfs\": {\n        \"type\": \"layers\",\n        \"diff_ids\": [\n          \"sha256:7cd52847ad775a5ddc4b58326cf884beee34544296402c6292ed76474c686d39\"\n        ]\n      },\n      \"config\": {\n        \"Cmd\": [\n          \"/bin/sh\"\n        ],\n        \"Env\": [\n          \"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"\n        ],\n        \"Image\": \"sha256:ba2beca50019d79fb31b12c08f3786c5a0621017a3e95a72f2f8b832f894a427\"\n      }\n    }\n  },\n  \"Results\": [\n    {\n      \"Target\": \"alpine:3.17.2 (alpine 3.17.2)\",\n      \"Class\": \"os-pkgs\",\n      \"Type\": \"alpine\",\n      \"Vulnerabilities\": [\n        {\n          \"VulnerabilityID\": \"CVE-2023-0464\",\n          \"PkgID\": \"libcrypto3@3.0.8-r0\",\n          \"PkgName\": \"libcrypto3\",\n          \"InstalledVersion\": \"3.0.8-r0\",\n          \"FixedVersion\": \"3.0.8-r1\",\n          \"Layer\": {\n            \"DiffID\": \"sha256:7cd52847ad775a5ddc4b58326cf884beee34544296402c6292ed76474c686d39\"\n          },\n          \"SeveritySource\": \"nvd\",\n          \"PrimaryURL\": \"https://avd.aquasec.com/nvd/cve-2023-0464\",\n          \"DataSource\": {\n            \"ID\": \"alpine\",\n            \"Name\": \"Alpine Secdb\",\n            \"URL\": \"https://secdb.alpinelinux.org/\"\n          },\n          \"Title\": \"Denial of service by excessive resource usage in verifying X509 policy constraints\",\n          \"Description\": \"A security vulnerability has been identified in all supported versions of OpenSSL related to the verification of X.509 certificate chains that include policy constraints. Attackers may be able to exploit this vulnerability by creating a malicious certificate chain that triggers exponential use of computational resources, leading to a denial-of-service (DoS) attack on affected systems. Policy processing is disabled by default but can be enabled by passing the `-policy' argument to the command line utilities or by calling the `X509_VERIFY_PARAM_set1_policies()' function.\",\n          \"Severity\": \"HIGH\",\n          \"CweIDs\": [\n            \"CWE-295\"\n          ],\n          \"CVSS\": {\n            \"nvd\": {\n              \"V3Vector\": \"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H\",\n              \"V3Score\": 7.5\n            },\n            \"redhat\": {\n              \"V3Vector\": \"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H\",\n              \"V3Score\": 5.9\n            }\n          },\n          \"References\": [\n            \"https://access.redhat.com/security/cve/CVE-2023-0464\",\n            \"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-0464\",\n            \"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=2017771e2db3e2b96f89bbe8766c3209f6a99545\",\n            \"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=2dcd4f1e3115f38cefa43e3efbe9b801c27e642e\",\n            \"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=879f7080d7e141f415c79eaa3a8ac4a3dad0348b\",\n            \"https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=959c59c7a0164117e7f8366466a32bb1f8d77ff1\",\n            \"https://nvd.nist.gov/vuln/detail/CVE-2023-0464\",\n            \"https://ubuntu.com/security/notices/USN-6039-1\",\n            \"https://www.cve.org/CVERecord?id=CVE-2023-0464\",\n            \"https://www.openssl.org/news/secadv/20230322.txt\"\n          ],\n          \"PublishedDate\": \"2023-03-22T17:15:00Z\",\n          \"LastModifiedDate\": \"2023-03-29T19:37:00Z\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n# Examples\n  * This library is built using itself! See [Jenkinsfile](Jenkinsfile)\n  * [cloudugo/cas](https://github.com/cloudogu/cas)\n  * [cloudogu/command-bus](https://github.com/cloudogu/command-bus)\n  * [cloudogu/continuous-delivery-slides-example](https://github.com/cloudogu/continuous-delivery-slides-example/)\n\n\n## What is the Cloudogu EcoSystem?\nThe Cloudogu EcoSystem is an open platform, which lets you choose how and where your team creates great software. Each service or tool is delivered as a Dogu, a Docker container. Each Dogu can easily be integrated in your environment just by pulling it from our registry.\n\nWe have a growing number of ready-to-use Dogus, e.g. SCM-Manager, Jenkins, Nexus Repository, SonarQube, Redmine and many more. Every Dogu can be tailored to your specific needs. Take advantage of a central authentication service, a dynamic navigation, that lets you easily switch between the web UIs and a smart configuration magic, which automatically detects and responds to dependencies between Dogus.\n\nThe Cloudogu EcoSystem is open source and it runs either on-premises or in the cloud. The Cloudogu EcoSystem is developed by Cloudogu GmbH under [AGPL-3.0-only](https://spdx.org/licenses/AGPL-3.0-only.html).\n\n## License\nCopyright © 2020 - present Cloudogu GmbH\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\nYou should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.\nSee [LICENSE](LICENSE) for details.\n\n\n---\nMADE WITH :heart:\u0026nbsp;FOR DEV ADDICTS. [Legal notice / Imprint](https://cloudogu.com/en/imprint/?mtm_campaign=ecosystem\u0026mtm_kwd=imprint\u0026mtm_source=github\u0026mtm_medium=link)\n","funding_links":[],"categories":["maven"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudogu%2Fces-build-lib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudogu%2Fces-build-lib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudogu%2Fces-build-lib/lists"}