From 333bbf05397258785a98b608c033abade708dbb8 Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Fri, 15 Sep 2023 17:37:41 +1000 Subject: [PATCH] Move jdbc daos classes to a separate plugin and make using H2 really optional now (Please refer to documentation when upgrading if you were using some jdbc storage) (#692) * Move jdbc daos classes to a separate plugin Signed-off-by: Olivier Lamy * better module name Signed-off-by: Olivier Lamy * make dao more dynamic Signed-off-by: Olivier Lamy * remove duplicated dependency Signed-off-by: Olivier Lamy * fix some javadoc link Signed-off-by: Olivier Lamy * fix Extension lookup of the dao Signed-off-by: Olivier Lamy * fix test by using H2 to record datas Signed-off-by: Olivier Lamy * merge master * fix test Signed-off-by: Olivier Lamy * this one need to be an hpi Signed-off-by: Olivier Lamy * fix test issue with default h2 Signed-off-by: Olivier Lamy * pipeline-maven-api needs to be a plugin for classloader and displaying all extensions of dao, move sql files in correct places as loaded by the database plugin Signed-off-by: Olivier Lamy * cleanup some code, make dynamic dao change really working Signed-off-by: Olivier Lamy * use lookupSingleton Signed-off-by: Olivier Lamy * add some documentation of database/dao choice Signed-off-by: Olivier Lamy * fix images Signed-off-by: Olivier Lamy * fix connection validation and dao creation in separate place Signed-off-by: Olivier Lamy * cannot use this with id null Signed-off-by: Olivier Lamy * fix dao init Signed-off-by: Olivier Lamy * use different h2 url for test Signed-off-by: Olivier Lamy * remove unused import Signed-off-by: Olivier Lamy * to avoid some nit comments on extra lines added by mistake Signed-off-by: Olivier Lamy * cleanup dependencies due to bad merge Signed-off-by: Olivier Lamy * avoid slf4j no log warning Signed-off-by: Olivier Lamy * i18n Signed-off-by: Olivier Lamy * use better package, do not have same package with classes in different modules Signed-off-by: Olivier Lamy * move jdbc test to database module Signed-off-by: Olivier Lamy * use specific db package as well Signed-off-by: Olivier Lamy * fix changes after ide refactoring Signed-off-by: Olivier Lamy * use an older version for maven-core, move it as provided as it is provided by maven distribution and such scope will avoid some security scans Signed-off-by: Olivier Lamy * add hpi.compatibleSinceVersion property Signed-off-by: Olivier Lamy * add note on daoClass field for CasC users Signed-off-by: Olivier Lamy * a release has been made before this PR get merged so increase this Signed-off-by: Olivier Lamy * improve doc per review Signed-off-by: Olivier Lamy * add a test using yaml file can build a mysql dao Signed-off-by: Olivier Lamy * extract the test which needs Docker apart as Testcontainers annotation is supported only at class level Signed-off-by: Olivier Lamy * CasC test for postgres as well Signed-off-by: Olivier Lamy * remove previous admin monitor which is useless now with the split into another plugin for the database and add an admin monitor to display error if jdbc url is configured to use a real jdbc but the pipeline-maven-database plugin is not installed Signed-off-by: Olivier Lamy * fix copy/paste Signed-off-by: Olivier Lamy * add license header and remove wrong author tag Signed-off-by: Olivier Lamy * restore dao pretty print display if dao != null Signed-off-by: Olivier Lamy --------- Signed-off-by: Olivier Lamy --- README.adoc | 27 +- docs/images/dao-choice.png | Bin 0 -> 24079 bytes docs/images/dao-list-database.png | Bin 0 -> 165583 bytes .../images/pipeline-maven-plugin-database.png | Bin 0 -> 63230 bytes jenkins-plugin/pom.xml | 65 +-- .../maven/GlobalPipelineMavenConfig.java | 369 +++--------------- ...pelineMavenDatabasePluginAdminMonitor.java | 58 +++ ...eDatabaseWarningAdministrativeMonitor.java | 49 --- .../GlobalPipelineMavenConfig/config.jelly | 13 +- .../message.jelly | 8 +- .../ConfigurationAsCodeNeedDockerTest.java | 117 ++++++ .../maven/ConfigurationAsCodeTest.java | 21 +- .../pipeline/maven/DependencyGraphTest.java | 7 + .../maven/GlobalPipelineMavenConfigTest.java | 11 +- ...gAdministrativeMonitorIntegrationTest.java | 120 ------ ...abaseWarningAdministrativeMonitorTest.java | 173 -------- ...lineTriggerRunListenerIntegrationTest.java | 7 + .../src/test/resources/logback-test.xml | 14 - .../maven/configuration-as-code_mysql.yml | 4 +- .../configuration-as-code_postgresql.yml | 5 +- .../pipeline/maven/expected_output_mysql.yml | 4 +- .../maven/expected_output_postgresql.yml | 5 +- maven-spy/pom.xml | 2 +- pipeline-maven-api/pom.xml | 29 ++ .../plugins/pipeline/maven/MavenArtifact.java | 0 .../pipeline/maven/MavenDependency.java | 0 ...stractPipelineMavenPluginDaoDecorator.java | 11 + .../pipeline/maven/dao/CacheStats.java | 0 ...omTypePipelineMavenPluginDaoDecorator.java | 0 ...toringPipelineMavenPluginDaoDecorator.java | 1 - .../maven/dao/PipelineMavenPluginDao.java | 64 ++- .../maven/dao/PipelineMavenPluginNullDao.java | 42 +- .../pipeline/maven/dao/UpstreamMemory.java | 4 +- .../src/main/resources/index.jelly | 4 + .../pipeline/maven/dao/Messages.properties | 1 + pipeline-maven-database/pom.xml | 84 ++++ .../db}/AbstractPipelineMavenPluginDao.java | 369 +++++++++++++++++- .../maven/db}/PipelineMavenPluginH2Dao.java | 34 +- .../db}/PipelineMavenPluginMySqlDao.java | 15 +- .../db}/PipelineMavenPluginPostgreSqlDao.java | 14 +- .../maven/db/migration/MigrationStep.java | 0 .../db/migration/h2/MigrationStep10.java | 0 .../db/migration/h2/MigrationStep11.java | 0 .../maven/db/migration/h2/MigrationStep8.java | 0 .../db/migration/mysql/MigrationStep12.java | 0 .../pipeline/maven/db}/util/ClassUtils.java | 2 +- .../maven/db}/util/RuntimeIoException.java | 2 +- .../maven/db}/util/RuntimeSqlException.java | 2 +- .../pipeline/maven/db}/util/SqlUtils.java | 2 +- .../src/main/resources/index.jelly | 4 + .../pipeline/maven/db/Messages.properties | 3 + .../main/resources/sql/h2/01_migration.sql | 0 .../main/resources/sql/h2/02_migration.sql | 0 .../main/resources/sql/h2/03_migration.sql | 0 .../main/resources/sql/h2/04_migration.sql | 0 .../main/resources/sql/h2/05_migration.sql | 0 .../main/resources/sql/h2/06_migration.sql | 0 .../main/resources/sql/h2/07_migration.sql | 0 .../main/resources/sql/h2/08_migration.sql | 0 .../main/resources/sql/h2/09_migration.sql | 0 .../main/resources/sql/h2/10_migration.sql | 0 .../main/resources/sql/h2/11_migration.sql | 0 .../main/resources/sql/h2/12_migration.sql | 0 .../main/resources/sql/mysql/01_migration.sql | 0 .../main/resources/sql/mysql/02_migration.sql | 0 .../main/resources/sql/mysql/03_migration.sql | 0 .../main/resources/sql/mysql/04_migration.sql | 0 .../main/resources/sql/mysql/05_migration.sql | 0 .../main/resources/sql/mysql/06_migration.sql | 0 .../main/resources/sql/mysql/07_migration.sql | 0 .../main/resources/sql/mysql/08_migration.sql | 0 .../main/resources/sql/mysql/09_migration.sql | 0 .../main/resources/sql/mysql/10_migration.sql | 0 .../main/resources/sql/mysql/11_migration.sql | 0 .../main/resources/sql/mysql/12_migration.sql | 0 .../main/resources/sql/mysql/13_migration.sql | 0 .../resources/sql/postgresql/01_migration.sql | 0 .../resources/sql/postgresql/02_migration.sql | 0 .../resources/sql/postgresql/03_migration.sql | 0 .../resources/sql/postgresql/04_migration.sql | 0 .../resources/sql/postgresql/05_migration.sql | 0 .../PipelineMavenPluginDaoAbstractTest.java | 4 +- ...ineMavenPluginH2DaoInitializationTest.java | 2 +- .../db}/PipelineMavenPluginH2DaoTest.java | 2 +- .../db}/PipelineMavenPluginMySqlDaoIT.java | 2 +- ...MavenPluginMySqlDaoInitializationTest.java | 2 +- .../db}/PipelineMavenPluginMySqlDaoTest.java | 2 +- .../PipelineMavenPluginPostgreSqlDaoIT.java | 2 +- .../PipelineMavenPluginPostgreSqlDaoTest.java | 2 +- .../maven/db}/util/ClassUtilsTest.java | 4 +- .../maven/db}/util/SqlTestsUtils.java | 4 +- .../pipeline/maven/util/classutils-test-1.txt | 0 pom.xml | 52 ++- 93 files changed, 1030 insertions(+), 814 deletions(-) create mode 100644 docs/images/dao-choice.png create mode 100644 docs/images/dao-list-database.png create mode 100644 docs/images/pipeline-maven-plugin-database.png create mode 100644 jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NeededPipelineMavenDatabasePluginAdminMonitor.java delete mode 100644 jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitor.java rename jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/{NonProductionGradeDatabaseWarningAdministrativeMonitor => NeededPipelineMavenDatabasePluginAdminMonitor}/message.jelly (73%) create mode 100644 jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeNeedDockerTest.java delete mode 100644 jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorIntegrationTest.java delete mode 100644 jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorTest.java delete mode 100644 jenkins-plugin/src/test/resources/logback-test.xml create mode 100644 pipeline-maven-api/pom.xml rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenArtifact.java (100%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenDependency.java (100%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDaoDecorator.java (96%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CacheStats.java (100%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CustomTypePipelineMavenPluginDaoDecorator.java (100%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/MonitoringPipelineMavenPluginDaoDecorator.java (99%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDao.java (89%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginNullDao.java (78%) rename {jenkins-plugin => pipeline-maven-api}/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/UpstreamMemory.java (84%) create mode 100644 pipeline-maven-api/src/main/resources/index.jelly create mode 100644 pipeline-maven-api/src/main/resources/org/jenkinsci/plugins/pipeline/maven/dao/Messages.properties create mode 100644 pipeline-maven-database/pom.xml rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/AbstractPipelineMavenPluginDao.java (76%) rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginH2Dao.java (84%) rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginMySqlDao.java (93%) rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginPostgreSqlDao.java (93%) rename {jenkins-plugin => pipeline-maven-database}/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/MigrationStep.java (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep10.java (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep11.java (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep8.java (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/mysql/MigrationStep12.java (100%) rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/util/ClassUtils.java (91%) rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/util/RuntimeIoException.java (93%) rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/util/RuntimeSqlException.java (93%) rename {jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven => pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db}/util/SqlUtils.java (92%) create mode 100644 pipeline-maven-database/src/main/resources/index.jelly create mode 100644 pipeline-maven-database/src/main/resources/org/jenkinsci/plugins/pipeline/maven/db/Messages.properties rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/01_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/02_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/03_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/04_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/05_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/06_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/07_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/08_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/09_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/10_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/11_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/h2/12_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/01_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/02_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/03_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/04_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/05_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/06_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/07_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/08_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/09_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/10_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/11_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/12_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/mysql/13_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/postgresql/01_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/postgresql/02_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/postgresql/03_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/postgresql/04_migration.sql (100%) rename {jenkins-plugin => pipeline-maven-database}/src/main/resources/sql/postgresql/05_migration.sql (100%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginDaoAbstractTest.java (99%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginH2DaoInitializationTest.java (99%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginH2DaoTest.java (97%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginMySqlDaoIT.java (98%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginMySqlDaoInitializationTest.java (99%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginMySqlDaoTest.java (98%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginPostgreSqlDaoIT.java (98%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/PipelineMavenPluginPostgreSqlDaoTest.java (97%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/util/ClassUtilsTest.java (72%) rename {jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven => pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db}/util/SqlTestsUtils.java (96%) rename {jenkins-plugin => pipeline-maven-database}/src/test/resources/org/jenkinsci/plugins/pipeline/maven/util/classutils-test-1.txt (100%) diff --git a/README.adoc b/README.adoc index 306b2ab5..8703628e 100644 --- a/README.adoc +++ b/README.adoc @@ -37,6 +37,9 @@ The **<> can be defined globally or at the folder This plugin allows transitioning smoothly from the legacy https://plugins.jenkins.io/maven-plugin/[Maven Integration] job type by allowing to reuse **<>** and by proposing the **<>**. + +Please note **per default some features will not be available** and you will have to change/configure a database storage which suits your environment. + toc::[] [#installation] @@ -46,8 +49,8 @@ The plugin can be found under the name `Pipeline Maven Integration Plugin` in th **For tests purposes only**, pre-releases (beta) versions are available in the https://updates.jenkins.io/#experimental-plugin-site[Experimental Plugin Site] and development versions (incremental releases) are archived on every successful build on https://ci.jenkins.io/job/Plugins/job/pipeline-maven-plugin/[our CI environment]. -CAUTION: **If you use the feature <> it is critical to <>** instead of the default embedded H2 instance. -**If you don't do it, it might degrade your environment stability** (The H2 database is running in your instance JVM and could request too many resources). +CAUTION: **If you want to use the feature <> it is critical to <>** as H2 is not preconfigured by default any more. +**Using H2 might degrade your environment stability** (The H2 database is running in your instance JVM and could request too many resources). [#changelog] == Changelog @@ -460,8 +463,8 @@ Trigger downstream pipeline that depend on Maven artifact generated by upstream * The downstream pipeline must have selected the build trigger `Build whenever a SNAPSHOT dependency is built` ** The build trigger can be defined at the pipeline level (`Build Triggers`), at the multibranch pipeline level (`Scan Repository Triggers`) or at the GitHub Organization / Bitbucket Project level (`Scan Organizations Triggers`) * You have to manually trigger once the upstream pipeline, and the downstream pipeline so that the link between the pipelines based on the SNAPSHOT dependency is established -* The dependency graph is, for the moment, exclusively stored in an H2 embedded database (`$JENKINS_HOME/jenkins-jobs/jenkins-jobs.mv.db`). -Support for an external H2 database and then for alternate databases (PostgreSQL) is on the roadmap (see https://github.com/jenkinsci/pipeline-maven-plugin/blob/pipeline-maven-3.0.0-beta-1/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2Dao.java[PipelineMavenPluginH2Dao.java]) +* The dependency graph is, for the moment, optionally stored in an H2 embedded database (`$JENKINS_HOME/jenkins-jobs/jenkins-jobs.mv.db`). And there is support + for PostgreSQL and MySql as well (see details below) ==== image:docs/images/trigger-downstream-1.png[] @@ -501,6 +504,22 @@ We want to quickly add reporters for CheckStyle, Jacoco... [#db-setup] == Database Setup +NOTE: Available since version 1332.xxxxxxxx.xxx + +To use a database you must first install the `Pipeline Maven Plugin Database` + +image::docs/images/pipeline-maven-plugin-database.png[] + +Have a look at the Tools configuration: + +image::docs/images/dao-choice.png[] + +The make a choice in available DAOs options: + +image::docs/images/dao-list-database.png[] + +For Configuration as Code users, these are the field to add into their yaml file `daoClass` and `jdbcUrl` + [#db-setup-mysql] === Using a MySQL Database diff --git a/docs/images/dao-choice.png b/docs/images/dao-choice.png new file mode 100644 index 0000000000000000000000000000000000000000..ff6eeedb97c26599e0158fad21f6bc8b57f5bb74 GIT binary patch literal 24079 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 K$Fh&QT>BT}jztpy literal 0 HcmV?d00001 diff --git a/docs/images/dao-list-database.png b/docs/images/dao-list-database.png new file mode 100644 index 0000000000000000000000000000000000000000..d2a99986dd99baf79c16ccafeade726c9580a7c2 GIT binary patch literal 165583 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%0D$KJeI_rat*$)6buGY*@`c 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
${instance.dao.toPrettyString()}
+
${instance.getDaoPrettyString()}
- + diff --git a/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitor/message.jelly b/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/NeededPipelineMavenDatabasePluginAdminMonitor/message.jelly similarity index 73% rename from jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitor/message.jelly rename to jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/NeededPipelineMavenDatabasePluginAdminMonitor/message.jelly index 9ea2d125..acb6102b 100644 --- a/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitor/message.jelly +++ b/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/NeededPipelineMavenDatabasePluginAdminMonitor/message.jelly @@ -23,12 +23,8 @@ THE SOFTWARE. --> - +
-
- - - - The Pipeline Maven Plugin is currently using an embedded H2 database. A production grade database, MySQL or PostgreSQL, should be used. + The Pipeline Maven Plugin is currently using a jdbc url for a database but the plugin pipeline-maven-database plugin is not installed
diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeNeedDockerTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeNeedDockerTest.java new file mode 100644 index 00000000..24f92612 --- /dev/null +++ b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeNeedDockerTest.java @@ -0,0 +1,117 @@ +package org.jenkinsci.plugins.pipeline.maven; + +import com.cloudbees.plugins.credentials.CredentialsProvider; +import hudson.ExtensionList; +import io.jenkins.plugins.casc.ConfigurationAsCode; +import io.jenkins.plugins.casc.ConfigurationContext; +import io.jenkins.plugins.casc.ConfiguratorRegistry; +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.pipeline.maven.dao.MonitoringPipelineMavenPluginDaoDecorator; +import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginNullDao; +import org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginMySqlDao; +import org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginPostgreSqlDao; +import org.junit.jupiter.api.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.junit.jupiter.WithJenkins; +import org.testcontainers.containers.MySQLContainer; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static io.jenkins.plugins.casc.misc.Util.*; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +@WithJenkins +@Testcontainers(disabledWithoutDocker = true) +public class ConfigurationAsCodeNeedDockerTest { + + @Container + public static MySQLContainer MYSQL_DB = new MySQLContainer<>(MySQLContainer.NAME).withUsername("aUser").withPassword("aPass"); + + @Container + public static PostgreSQLContainer POSTGRE_DB = new PostgreSQLContainer<>(PostgreSQLContainer.IMAGE).withUsername("aUser").withPassword("aPass"); + + @Test + public void should_support_mysql_configuration(JenkinsRule r) throws Exception { + + try { + MYSQL_DB.start(); + ExtensionList extensionList = r.jenkins.getExtensionList(CredentialsProvider.class); + extensionList.add(extensionList.size(), new GlobalPipelineMavenConfigTest.FakeCredentialsProvider()); + String jdbcUrl = MYSQL_DB.getJdbcUrl(); + + String yamlContent = toStringFromYamlFile(this, "configuration-as-code_mysql.yml"); + yamlContent = StringUtils.replace(yamlContent, "theJdbcUrl", jdbcUrl); + + Path tmpYml = Files.createTempFile("pipeline-maven-plugin-test", "yml"); + Files.write(tmpYml, yamlContent.getBytes()); + + ConfigurationAsCode.get().configure(singletonList(tmpYml.toFile().getAbsolutePath())); + + GlobalPipelineMavenConfig config = r.jenkins.getExtensionList(GlobalPipelineMavenConfig.class).get(0); + + assertThat(config.getJdbcUrl()).isEqualTo(jdbcUrl); + assertThat(config.getProperties()).isEqualTo("dataSource.cachePrepStmts=true\ndataSource.prepStmtCacheSize=250\n"); + assertThat(config.getDaoClass()).isEqualTo(PipelineMavenPluginMySqlDao.class.getName()); + + // we can't really test the PipelineMavenPluginMySqlDao is used as it is plenty of layers + // which doesn't expose the real implementation + assertThat(config.getDao().getClass()).isNotEqualTo(PipelineMavenPluginMySqlDao.class); + assertThat(config.getDao().getClass()).isNotEqualTo(PipelineMavenPluginNullDao.class); + assertThat(config.getDao().getClass()).isEqualTo(MonitoringPipelineMavenPluginDaoDecorator.class); + + ConfiguratorRegistry registry = ConfiguratorRegistry.get(); + ConfigurationContext context = new ConfigurationContext(registry); + String exported = toYamlString(getToolRoot(context).get("pipelineMaven")); + String expected = toStringFromYamlFile(this, "expected_output_mysql.yml"); + expected = StringUtils.replace(expected, "theJdbcUrl", jdbcUrl); + assertThat(exported).isEqualTo(expected); + } finally { + MYSQL_DB.stop(); + } + } + + @Test + public void should_support_postgres_configuration(JenkinsRule r) throws Exception { + + try { + POSTGRE_DB.start(); + ExtensionList extensionList = r.jenkins.getExtensionList(CredentialsProvider.class); + extensionList.add(extensionList.size(), new GlobalPipelineMavenConfigTest.FakeCredentialsProvider()); + String jdbcUrl = POSTGRE_DB.getJdbcUrl(); + + String yamlContent = toStringFromYamlFile(this, "configuration-as-code_postgresql.yml"); + yamlContent = StringUtils.replace(yamlContent, "theJdbcUrl", jdbcUrl); + + Path tmpYml = Files.createTempFile("pipeline-maven-plugin-test", "yml"); + Files.write(tmpYml, yamlContent.getBytes()); + + ConfigurationAsCode.get().configure(singletonList(tmpYml.toFile().getAbsolutePath())); + + GlobalPipelineMavenConfig config = r.jenkins.getExtensionList(GlobalPipelineMavenConfig.class).get(0); + + assertThat(config.getJdbcUrl()).isEqualTo(jdbcUrl); + assertThat(config.getDaoClass()).isEqualTo(PipelineMavenPluginPostgreSqlDao.class.getName()); + + // we can't really test the PipelineMavenPluginPostgreSqlDao is used as it is plenty of layers + // which doesn't expose the real implementation + assertThat(config.getDao().getClass()).isNotEqualTo(PipelineMavenPluginPostgreSqlDao.class); + assertThat(config.getDao().getClass()).isNotEqualTo(PipelineMavenPluginNullDao.class); + assertThat(config.getDao().getClass()).isEqualTo(MonitoringPipelineMavenPluginDaoDecorator.class); + + ConfiguratorRegistry registry = ConfiguratorRegistry.get(); + ConfigurationContext context = new ConfigurationContext(registry); + String exported = toYamlString(getToolRoot(context).get("pipelineMaven")); + String expected = toStringFromYamlFile(this, "expected_output_postgresql.yml"); + expected = StringUtils.replace(expected, "theJdbcUrl", jdbcUrl); + assertThat(exported).isEqualTo(expected); + } finally { + POSTGRE_DB.stop(); + } + } + +} diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeTest.java index 3e7b4c5c..1bb9fe73 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeTest.java +++ b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/ConfigurationAsCodeTest.java @@ -79,31 +79,14 @@ public void should_support_triggers_configuration(JenkinsRule r) throws Exceptio assertThat(exported).isEqualTo(expected); } - @Test - public void should_support_mysql_configuration(JenkinsRule r) throws Exception { - ConfigurationAsCode.get().configure(singletonList(getClass().getResource("configuration-as-code_mysql.yml").toExternalForm())); - - GlobalPipelineMavenConfig config = r.jenkins.getExtensionList(GlobalPipelineMavenConfig.class).get(0); - - assertThat(config.getJdbcUrl()).isEqualTo("jdbc:mysql://dbserver/jenkinsdb"); - assertThat(config.getProperties()).isEqualTo("dataSource.cachePrepStmts=true\ndataSource.prepStmtCacheSize=250\n"); - - ConfiguratorRegistry registry = ConfiguratorRegistry.get(); - ConfigurationContext context = new ConfigurationContext(registry); - String exported = toYamlString(getToolRoot(context).get("pipelineMaven")); - String expected = toStringFromYamlFile(this, "expected_output_mysql.yml"); - - assertThat(exported).isEqualTo(expected); - } - @Test public void should_support_postgresql_configuration(JenkinsRule r) throws Exception { ConfigurationAsCode.get().configure(singletonList(getClass().getResource("configuration-as-code_postgresql.yml").toExternalForm())); GlobalPipelineMavenConfig config = r.jenkins.getExtensionList(GlobalPipelineMavenConfig.class).get(0); - assertThat(config.getJdbcUrl()).isEqualTo("jdbc:postgresql://dbserver/jenkinsdb"); - assertThat(config.getJdbcCredentialsId()).isEqualTo("pg-creds"); + assertThat(config.getJdbcUrl()).isEqualTo("theJdbcUrl"); + assertThat(config.getJdbcCredentialsId()).isEqualTo("credsId"); ConfiguratorRegistry registry = ConfiguratorRegistry.get(); ConfigurationContext context = new ConfigurationContext(registry); diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/DependencyGraphTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/DependencyGraphTest.java index 9199be4e..4602f155 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/DependencyGraphTest.java +++ b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/DependencyGraphTest.java @@ -4,12 +4,15 @@ import static org.jenkinsci.plugins.pipeline.maven.TestUtils.runAfterMethod; import static org.jenkinsci.plugins.pipeline.maven.TestUtils.runBeforeMethod; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Future; import java.util.stream.Collectors; +import hudson.ExtensionList; import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginDao; +import org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginH2Dao; import org.jenkinsci.plugins.pipeline.maven.publishers.PipelineGraphPublisher; import org.jenkinsci.plugins.pipeline.maven.trigger.WorkflowJobDependencyTrigger; import org.jenkinsci.plugins.pipeline.maven.util.WorkflowMultibranchProjectTestsUtils; @@ -39,6 +42,10 @@ public class DependencyGraphTest extends AbstractIntegrationTest { @BeforeEach public void setup() throws Exception { + ExtensionList.lookupSingleton(GlobalPipelineMavenConfig.class).setDaoClass(PipelineMavenPluginH2Dao.class.getName()); + String jdbcUrl = "jdbc:h2:file:" + new File("target", getClass().getName() + "-h2").getAbsolutePath() + ";" + + "AUTO_SERVER=TRUE;MULTI_THREADED=1;QUERY_CACHE_SIZE=25;JMX=TRUE"; + ExtensionList.lookupSingleton(GlobalPipelineMavenConfig.class).setJdbcUrl(jdbcUrl); downstreamArtifactRepoRule = new GitSampleRepoRule(); runBeforeMethod(downstreamArtifactRepoRule); diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfigTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfigTest.java index 763049ca..7b1b2536 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfigTest.java +++ b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfigTest.java @@ -13,9 +13,9 @@ import org.jenkinsci.plugins.pipeline.maven.dao.CustomTypePipelineMavenPluginDaoDecorator; import org.jenkinsci.plugins.pipeline.maven.dao.MonitoringPipelineMavenPluginDaoDecorator; import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginDao; -import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginH2Dao; -import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginMySqlDao; -import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginPostgreSqlDao; +import org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginH2Dao; +import org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginMySqlDao; +import org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginPostgreSqlDao; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.jvnet.hudson.test.JenkinsRule; @@ -55,7 +55,7 @@ public static void setup(JenkinsRule r) { private static JenkinsRule j; - private static class FakeCredentialsProvider extends CredentialsProvider { + public static class FakeCredentialsProvider extends CredentialsProvider { public FakeCredentialsProvider() { } @@ -80,6 +80,7 @@ public List getCredentials(Class type, ItemGroup i @Test public void shouldBuildH2Dao() throws Exception { + config.setDaoClass(PipelineMavenPluginH2Dao.class.getName()); PipelineMavenPluginDao dao = config.getDao(); assertThat(dao).isInstanceOf(MonitoringPipelineMavenPluginDaoDecorator.class); @@ -91,6 +92,7 @@ public void shouldBuildH2Dao() throws Exception { @Test public void shouldBuildMysqlDao() throws Exception { + config.setDaoClass(PipelineMavenPluginMySqlDao.class.getName()); ExtensionList extensionList = Jenkins.getInstance().getExtensionList(CredentialsProvider.class); extensionList.add(extensionList.size(), new FakeCredentialsProvider()); config.setJdbcUrl(MYSQL_DB.getJdbcUrl()); @@ -125,6 +127,7 @@ public void shouldBuildMysqlDao() throws Exception { @Test public void shouldBuildPostgresqlDao() throws Exception { + config.setDaoClass(PipelineMavenPluginPostgreSqlDao.class.getName()); ExtensionList extensionList = Jenkins.getInstance().getExtensionList(CredentialsProvider.class); extensionList.add(extensionList.size(), new FakeCredentialsProvider()); config.setJdbcUrl(POSTGRE_DB.getJdbcUrl()); diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorIntegrationTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorIntegrationTest.java deleted file mode 100644 index 8d7f35d1..00000000 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorIntegrationTest.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.jenkinsci.plugins.pipeline.maven; - -import static com.cloudbees.plugins.credentials.CredentialsScope.GLOBAL; -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; - -import org.acegisecurity.Authentication; -import org.junit.jupiter.api.Test; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.junit.jupiter.WithJenkins; -import org.testcontainers.containers.MySQLContainer; -import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import com.cloudbees.plugins.credentials.Credentials; -import com.cloudbees.plugins.credentials.CredentialsProvider; -import com.cloudbees.plugins.credentials.domains.DomainRequirement; -import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl; - -import hudson.ExtensionList; -import hudson.model.AdministrativeMonitor; -import hudson.model.ItemGroup; - -@Testcontainers(disabledWithoutDocker = true) -@WithJenkins -public class NonProductionGradeDatabaseWarningAdministrativeMonitorIntegrationTest { - - @Container - public static MySQLContainer MYSQL_DB = new MySQLContainer<>(MySQLContainer.NAME).withUsername("aUser").withPassword("aPass"); - - @Container - public static PostgreSQLContainer POSTGRE_DB = new PostgreSQLContainer<>(PostgreSQLContainer.IMAGE).withUsername("aUser").withPassword("aPass"); - - private static class FakeCredentialsProvider extends CredentialsProvider { - public FakeCredentialsProvider() { - } - - @Override - public boolean isEnabled(Object context) { - return true; - } - - @Override - public List getCredentials(Class type, ItemGroup itemGroup, Authentication authentication, - List domainRequirements) { - return (List) asList(new UsernamePasswordCredentialsImpl(GLOBAL, "credsId", "", "aUser", "aPass")); - } - - @Override - public List getCredentials(Class type, ItemGroup itemGroup, Authentication authentication) { - return getCredentials(type, itemGroup, authentication, null); - } - } - - @Test - public void shouldMitigateComputationWithH2Database(JenkinsRule j) throws Exception { - NonProductionGradeDatabaseWarningAdministrativeMonitor monitor = j.getInstance().getExtensionList(AdministrativeMonitor.class) - .get(NonProductionGradeDatabaseWarningAdministrativeMonitor.class); - assertThat(monitor).isNotNull(); - - assertThat(GlobalPipelineMavenConfig.get().isDaoInitialized()).isFalse(); - assertThat(monitor.isActivated()).isFalse(); - - GlobalPipelineMavenConfig.get().setJdbcUrl("jdbc:h2:file:/tmp/some.file"); - - assertThat(GlobalPipelineMavenConfig.get().isDaoInitialized()).isFalse(); - assertThat(monitor.isActivated()).isTrue(); - - GlobalPipelineMavenConfig.get().setJdbcUrl(null); - - assertThat(GlobalPipelineMavenConfig.get().isDaoInitialized()).isFalse(); - assertThat(monitor.isActivated()).isFalse(); - - GlobalPipelineMavenConfig.get().getDao(); - - assertThat(GlobalPipelineMavenConfig.get().isDaoInitialized()).isTrue(); - assertThat(monitor.isActivated()).isFalse(); - - for (int i = 1; i <= 101; i++) { - GlobalPipelineMavenConfig.get().getDao().recordGeneratedArtifact("a job", i, "a.group.id", "anArtifactId", "1.0.0-SNAPSHOT", "jar", - "1.0.0-SNAPSHOT", null, false, "jar", null); - } - - assertThat(GlobalPipelineMavenConfig.get().isDaoInitialized()).isTrue(); - assertThat(monitor.isActivated()).isTrue(); - } - - @Test - public void shouldNotDisplayWarningWithMysqlDatabase(JenkinsRule j) throws Exception { - ExtensionList extensionList = j.getInstance().getExtensionList(CredentialsProvider.class); - extensionList.add(extensionList.size(), new FakeCredentialsProvider()); - GlobalPipelineMavenConfig.get().setJdbcUrl(MYSQL_DB.getJdbcUrl()); - GlobalPipelineMavenConfig.get().setJdbcCredentialsId("credsId"); - - NonProductionGradeDatabaseWarningAdministrativeMonitor monitor = j.jenkins.getExtensionList(AdministrativeMonitor.class) - .get(NonProductionGradeDatabaseWarningAdministrativeMonitor.class); - - assertThat(monitor).isNotNull(); - assertThat(GlobalPipelineMavenConfig.get().isDaoInitialized()).isFalse(); - assertThat(monitor.isActivated()).isFalse(); - } - - @Test - public void shouldNotDisplayWarningWithPostgresDatabase(JenkinsRule j) throws Exception { - ExtensionList extensionList = j.getInstance().getExtensionList(CredentialsProvider.class); - extensionList.add(extensionList.size(), new FakeCredentialsProvider()); - GlobalPipelineMavenConfig.get().setJdbcUrl(POSTGRE_DB.getJdbcUrl()); - GlobalPipelineMavenConfig.get().setJdbcCredentialsId("credsId"); - - NonProductionGradeDatabaseWarningAdministrativeMonitor monitor = j.jenkins.getExtensionList(AdministrativeMonitor.class) - .get(NonProductionGradeDatabaseWarningAdministrativeMonitor.class); - - assertThat(monitor).isNotNull(); - assertThat(GlobalPipelineMavenConfig.get().isDaoInitialized()).isFalse(); - assertThat(monitor.isActivated()).isFalse(); - } -} diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorTest.java deleted file mode 100644 index 2d3e741e..00000000 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitorTest.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.jenkinsci.plugins.pipeline.maven; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginDao; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockedStatic; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class NonProductionGradeDatabaseWarningAdministrativeMonitorTest { - - @InjectMocks - private NonProductionGradeDatabaseWarningAdministrativeMonitor monitor; - - @Mock - private GlobalPipelineMavenConfig config; - - @Mock - private PipelineMavenPluginDao dao; - - @Test - public void test_is_activated_no_config_and_uninitialized() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn(null); - when(config.isDaoInitialized()).thenReturn(false); - - assertThat(monitor.isActivated()).isFalse(); - - verify(config).getJdbcUrl(); - verify(config).isDaoInitialized(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_empty_config_and_uninitialized() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn(""); - when(config.isDaoInitialized()).thenReturn(false); - - assertThat(monitor.isActivated()).isFalse(); - - verify(config).getJdbcUrl(); - verify(config).isDaoInitialized(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_no_config_and_initialized_non_production() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn(null); - when(config.isDaoInitialized()).thenReturn(true); - when(config.getDao()).thenReturn(dao); - when(dao.isEnoughProductionGradeForTheWorkload()).thenReturn(false); - - assertThat(monitor.isActivated()).isTrue(); - - verify(config).getJdbcUrl(); - verify(config).getDao(); - verify(config).isDaoInitialized(); - verify(dao).isEnoughProductionGradeForTheWorkload(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_empty_config_and_initialized_non_production() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn(""); - when(config.isDaoInitialized()).thenReturn(true); - when(config.getDao()).thenReturn(dao); - when(dao.isEnoughProductionGradeForTheWorkload()).thenReturn(false); - - assertThat(monitor.isActivated()).isTrue(); - - verify(config).getJdbcUrl(); - verify(config).getDao(); - verify(config).isDaoInitialized(); - verify(dao).isEnoughProductionGradeForTheWorkload(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_no_config_and_initialized_production() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn(null); - when(config.isDaoInitialized()).thenReturn(true); - when(config.getDao()).thenReturn(dao); - when(dao.isEnoughProductionGradeForTheWorkload()).thenReturn(true); - - assertThat(monitor.isActivated()).isFalse(); - - verify(config).getJdbcUrl(); - verify(config).getDao(); - verify(config).isDaoInitialized(); - verify(dao).isEnoughProductionGradeForTheWorkload(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_empty_config_and_initialized_production() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn(""); - when(config.isDaoInitialized()).thenReturn(true); - when(config.getDao()).thenReturn(dao); - when(dao.isEnoughProductionGradeForTheWorkload()).thenReturn(true); - - assertThat(monitor.isActivated()).isFalse(); - - verify(config).getJdbcUrl(); - verify(config).getDao(); - verify(config).isDaoInitialized(); - verify(dao).isEnoughProductionGradeForTheWorkload(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_with_h2_config() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn("jdbc:h2:some url"); - - assertThat(monitor.isActivated()).isTrue(); - - verify(config).getJdbcUrl(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_with_mysql_config() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn("jdbc:mysql:some url"); - - assertThat(monitor.isActivated()).isFalse(); - - verify(config).getJdbcUrl(); - verifyNoMoreInteractions(config, dao); - } - } - - @Test - public void test_is_activated_with_postgresql_config() { - try (MockedStatic c = mockStatic(GlobalPipelineMavenConfig.class)) { - c.when(GlobalPipelineMavenConfig::get).thenReturn(config); - when(config.getJdbcUrl()).thenReturn("jdbc:postgresql:some url"); - - assertThat(monitor.isActivated()).isFalse(); - - verify(config).getJdbcUrl(); - verifyNoMoreInteractions(config, dao); - } - } -} diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/listeners/DownstreamPipelineTriggerRunListenerIntegrationTest.java b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/listeners/DownstreamPipelineTriggerRunListenerIntegrationTest.java index e2f43aff..30de9202 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/listeners/DownstreamPipelineTriggerRunListenerIntegrationTest.java +++ b/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/listeners/DownstreamPipelineTriggerRunListenerIntegrationTest.java @@ -3,14 +3,17 @@ import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +import java.io.File; import java.util.ArrayList; import java.util.List; +import hudson.ExtensionList; import org.jenkinsci.plugins.pipeline.maven.AbstractIntegrationTest; import org.jenkinsci.plugins.pipeline.maven.GlobalPipelineMavenConfig; import org.jenkinsci.plugins.pipeline.maven.MavenArtifact; import org.jenkinsci.plugins.pipeline.maven.MavenDependency; import org.jenkinsci.plugins.pipeline.maven.MavenPublisher; +import org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginH2Dao; import org.jenkinsci.plugins.pipeline.maven.publishers.FindbugsAnalysisPublisher; import org.jenkinsci.plugins.pipeline.maven.publishers.PipelineGraphPublisher; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; @@ -34,6 +37,10 @@ public class DownstreamPipelineTriggerRunListenerIntegrationTest extends Abstrac @BeforeEach public void setup() throws Exception { + ExtensionList.lookupSingleton(GlobalPipelineMavenConfig.class).setDaoClass(PipelineMavenPluginH2Dao.class.getName()); + String jdbcUrl = "jdbc:h2:file:" + new File("target", getClass().getName() + "-h2").getAbsolutePath() + ";" + + "AUTO_SERVER=TRUE;MULTI_THREADED=1;QUERY_CACHE_SIZE=25;JMX=TRUE"; + ExtensionList.lookupSingleton(GlobalPipelineMavenConfig.class).setJdbcUrl(jdbcUrl); List publisherOptions = GlobalPipelineMavenConfig.get().getPublisherOptions(); if (publisherOptions == null) { publisherOptions = new ArrayList<>(); diff --git a/jenkins-plugin/src/test/resources/logback-test.xml b/jenkins-plugin/src/test/resources/logback-test.xml deleted file mode 100644 index 3ec10b26..00000000 --- a/jenkins-plugin/src/test/resources/logback-test.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %logger{36} - %msg%n - - - - - - - - - \ No newline at end of file diff --git a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_mysql.yml b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_mysql.yml index 8029be5a..ea176970 100644 --- a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_mysql.yml +++ b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_mysql.yml @@ -3,7 +3,9 @@ jenkins: tool: pipelineMaven: - jdbcUrl: jdbc:mysql://dbserver/jenkinsdb + jdbcUrl: theJdbcUrl + daoClass: org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginMySqlDao + jdbcCredentialsId: credsId properties: | dataSource.cachePrepStmts=true dataSource.prepStmtCacheSize=250 diff --git a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_postgresql.yml b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_postgresql.yml index a6f2a162..96ab35e5 100644 --- a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_postgresql.yml +++ b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/configuration-as-code_postgresql.yml @@ -3,5 +3,6 @@ jenkins: tool: pipelineMaven: - jdbcUrl: jdbc:postgresql://dbserver/jenkinsdb - JdbcCredentialsId: pg-creds + jdbcUrl: theJdbcUrl + daoClass: org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginPostgreSqlDao + JdbcCredentialsId: credsId diff --git a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_mysql.yml b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_mysql.yml index 0d82fece..6e398d5e 100644 --- a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_mysql.yml +++ b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_mysql.yml @@ -1,5 +1,7 @@ +daoClass: "org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginMySqlDao" globalTraceability: false -jdbcUrl: "jdbc:mysql://dbserver/jenkinsdb" +jdbcCredentialsId: "credsId" +jdbcUrl: "theJdbcUrl" properties: | dataSource.cachePrepStmts=true dataSource.prepStmtCacheSize=250 diff --git a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_postgresql.yml b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_postgresql.yml index 2bb67dbb..d221548e 100644 --- a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_postgresql.yml +++ b/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/expected_output_postgresql.yml @@ -1,6 +1,7 @@ +daoClass: "org.jenkinsci.plugins.pipeline.maven.db.PipelineMavenPluginPostgreSqlDao" globalTraceability: false -jdbcCredentialsId: "pg-creds" -jdbcUrl: "jdbc:postgresql://dbserver/jenkinsdb" +jdbcCredentialsId: "credsId" +jdbcUrl: "theJdbcUrl" triggerDownstreamUponResultAborted: false triggerDownstreamUponResultFailure: false triggerDownstreamUponResultNotBuilt: false diff --git a/maven-spy/pom.xml b/maven-spy/pom.xml index 2bce893c..0cb867de 100644 --- a/maven-spy/pom.xml +++ b/maven-spy/pom.xml @@ -46,7 +46,7 @@ org.apache.maven maven-core - 3.3.9 + provided org.sonatype.aether diff --git a/pipeline-maven-api/pom.xml b/pipeline-maven-api/pom.xml new file mode 100644 index 00000000..6dd37edd --- /dev/null +++ b/pipeline-maven-api/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + org.jenkins-ci.plugins + pipeline-maven-parent + ${changelist} + + pipeline-maven-api + Pipeline Maven Plugin API + hpi + + + + org.apache.maven + maven-artifact + + + org.apache.maven.resolver + maven-resolver-api + 1.7.3 + + + org.slf4j + slf4j-simple + + + + diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenArtifact.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenArtifact.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenArtifact.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenArtifact.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenDependency.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenDependency.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenDependency.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/MavenDependency.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDaoDecorator.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDaoDecorator.java similarity index 96% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDaoDecorator.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDaoDecorator.java index 24bb814d..91b9fbe4 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDaoDecorator.java +++ b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDaoDecorator.java @@ -5,6 +5,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; + import java.io.IOException; import java.util.List; import java.util.Map; @@ -18,6 +19,16 @@ public AbstractPipelineMavenPluginDaoDecorator(@NonNull PipelineMavenPluginDao d this.delegate = delegate; } + @Override + public String getDescription() { + return delegate.getDescription(); + } + + @Override + public Builder getBuilder() { + return delegate.getBuilder(); + } + @Override public void recordDependency(@NonNull String jobFullName, int buildNumber, @NonNull String groupId, @NonNull String artifactId, @NonNull String version, @NonNull String type, @NonNull String scope, boolean ignoreUpstreamTriggers, String classifier) { delegate.recordDependency(jobFullName, buildNumber, groupId, artifactId, version, type, scope, ignoreUpstreamTriggers, classifier); diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CacheStats.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CacheStats.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CacheStats.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CacheStats.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CustomTypePipelineMavenPluginDaoDecorator.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CustomTypePipelineMavenPluginDaoDecorator.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CustomTypePipelineMavenPluginDaoDecorator.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/CustomTypePipelineMavenPluginDaoDecorator.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/MonitoringPipelineMavenPluginDaoDecorator.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/MonitoringPipelineMavenPluginDaoDecorator.java similarity index 99% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/MonitoringPipelineMavenPluginDaoDecorator.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/MonitoringPipelineMavenPluginDaoDecorator.java index e196a680..47ed96b4 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/MonitoringPipelineMavenPluginDaoDecorator.java +++ b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/MonitoringPipelineMavenPluginDaoDecorator.java @@ -2,7 +2,6 @@ import org.jenkinsci.plugins.pipeline.maven.MavenArtifact; import org.jenkinsci.plugins.pipeline.maven.MavenDependency; -import org.jenkinsci.plugins.pipeline.maven.listeners.DaoHelper; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDao.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDao.java similarity index 89% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDao.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDao.java index 43289bea..ac962556 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDao.java +++ b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDao.java @@ -26,10 +26,10 @@ import hudson.model.Item; import hudson.model.Run; +import hudson.util.FormValidation; import org.apache.maven.artifact.Artifact; import org.jenkinsci.plugins.pipeline.maven.MavenArtifact; import org.jenkinsci.plugins.pipeline.maven.MavenDependency; -import org.jenkinsci.plugins.pipeline.maven.publishers.PipelineGraphPublisher; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -52,7 +52,7 @@ public interface PipelineMavenPluginDao extends Closeable { * @param version Maven dependency version * @param type Maven dependency type (e.g. "jar", "war", "pom", hpi"...) * @param scope Maven dependency scope ("compile", "test", "provided"...) - * @param ignoreUpstreamTriggers see {@link PipelineGraphPublisher#isIgnoreUpstreamTriggers()} ()} + * @param ignoreUpstreamTriggers see PipelineGraphPublisher#isIgnoreUpstreamTriggers() * @param classifier Maven dependency classifier */ void recordDependency(@NonNull String jobFullName, int buildNumber, @@ -67,7 +67,7 @@ void recordDependency(@NonNull String jobFullName, int buildNumber, * @param parentGroupId Maven dependency groupId * @param parentArtifactId Maven dependency artifactId * @param parentVersion Maven dependency version - * @param ignoreUpstreamTriggers see {@link PipelineGraphPublisher#isIgnoreUpstreamTriggers()} ()} + * @param ignoreUpstreamTriggers see PipelineGraphPublisher#isIgnoreUpstreamTriggers() */ void recordParentProject(@NonNull String jobFullName, int buildNumber, @NonNull String parentGroupId, @NonNull String parentArtifactId, @NonNull String parentVersion, @@ -85,7 +85,7 @@ void recordParentProject(@NonNull String jobFullName, int buildNumber, * (e.g. baseVersion is "1.1-SNAPSHOT" for a "1.1-SNAPSHOT" artifact that has been deployed to a repo and expanded * to "1.1-20170808.155524-66") * @param repositoryUrl URL of the Maven repository on which the artifact is deployed ("mvn deploy"). {@code null} if the artifact was not deployed - * @param skipDownstreamTriggers see {@link PipelineGraphPublisher#isSkipDownstreamTriggers()} + * @param skipDownstreamTriggers see PipelineGraphPublisher#isSkipDownstreamTriggers() * @param extension * @param classifier */ @@ -94,7 +94,7 @@ void recordGeneratedArtifact(@NonNull String jobFullName, int buildNumber, @Nullable String repositoryUrl, boolean skipDownstreamTriggers, String extension, String classifier); /** - * TODO add {@link MavenArtifact} as {@link org.jenkinsci.plugins.pipeline.maven.cause.MavenDependencyUpstreamCause} gives these details + * TODO add {@link MavenArtifact} as org.jenkinsci.plugins.pipeline.maven.cause.MavenDependencyUpstreamCause gives these details * @param upstreamJobName Job that triggered the build. See {@link Item#getFullName()}. * @param upstreamBuildNumber Job that triggered the build. See {@link Run#getNumber()}. * @param downstreamJobName Job that is triggered. See {@link Item#getFullName()}. @@ -262,6 +262,8 @@ default SortedSet listDownstreamJobs(@NonNull String groupId, @NonNull S */ String toPrettyString(); + String getDescription(); + /** * Update the database with build result details. @@ -282,4 +284,56 @@ default SortedSet listDownstreamJobs(@NonNull String groupId, @NonNull S * @return {@code false} if the underlying database is not production grade enough for the workload */ boolean isEnoughProductionGradeForTheWorkload(); + + interface Builder { + class Config { + private String jdbcUrl; + + private String credentialsId; + + private String properties; + + public String getJdbcUrl() { + return jdbcUrl; + } + + public Config jdbcUrl(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + return this; + } + + public String getCredentialsId() { + return this.credentialsId; + } + + public Config credentialsId(String credentialsId) { + this.credentialsId = credentialsId; + return this; + } + + public String getProperties() { + return this.properties; + } + + public Config properties(String properties) { + this.properties = properties; + return this; + } + + public Config() { + // + } + } + + PipelineMavenPluginDao build(Config config); + + FormValidation validateConfiguration(Config config); + + } + + Builder getBuilder(); + + default String getDefaultJdbcUrl() { + return null; + } } diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginNullDao.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginNullDao.java similarity index 78% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginNullDao.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginNullDao.java index d69e11a3..31212042 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginNullDao.java +++ b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginNullDao.java @@ -24,10 +24,13 @@ package org.jenkinsci.plugins.pipeline.maven.dao; +import hudson.Extension; +import hudson.util.FormValidation; import org.jenkinsci.plugins.pipeline.maven.MavenArtifact; import org.jenkinsci.plugins.pipeline.maven.MavenDependency; import edu.umd.cs.findbugs.annotations.NonNull; + import java.io.IOException; import java.util.Collections; import java.util.List; @@ -40,12 +43,33 @@ /** * @author Cyrille Le Clerc */ +@Extension public class PipelineMavenPluginNullDao implements PipelineMavenPluginDao { private static Logger LOGGER = Logger.getLogger(PipelineMavenPluginNullDao.class.getName()); + @Override + public String getDescription() { + return Messages.dao_null_description(); + } + + @Override + public PipelineMavenPluginDao.Builder getBuilder() { + return new Builder() { + @Override + public PipelineMavenPluginDao build(Config config) { + return new PipelineMavenPluginNullDao(); + } + + @Override + public FormValidation validateConfiguration(Config config) { + return FormValidation.ok(); + } + }; + } + @Override public void recordDependency(String jobFullName, int buildNumber, String groupId, String artifactId, String version, String type, String scope, boolean ignoreUpstreamTriggers, String classifier) { - LOGGER.log(Level.INFO, "recordDependency({0}#{1}, {2}:{3}:{4}:{5}, {6}, ignoreUpstreamTriggers:{7}})", + LOGGER.log(Level.FINEST, "NOT recordDependency({0}#{1}, {2}:{3}:{4}:{5}, {6}, ignoreUpstreamTriggers:{7}})", new Object[]{jobFullName, buildNumber, groupId, artifactId, version, type, scope, ignoreUpstreamTriggers}); } @@ -57,39 +81,39 @@ public List listDependencies(@NonNull String jobFullName, int b @Override public void recordParentProject(@NonNull String jobFullName, int buildNumber, @NonNull String parentGroupId, @NonNull String parentArtifactId, @NonNull String parentVersion, boolean ignoreUpstreamTriggers) { - LOGGER.log(Level.INFO, "recordParentProject({0}#{1}, {2}:{3} ignoreUpstreamTriggers:{5}})", + LOGGER.log(Level.FINEST, "NOT recordParentProject({0}#{1}, {2}:{3} ignoreUpstreamTriggers:{5}})", new Object[]{jobFullName, buildNumber, parentGroupId, parentArtifactId, parentVersion, ignoreUpstreamTriggers}); } @Override public void recordGeneratedArtifact(String jobFullName, int buildNumber, String groupId, String artifactId, String version, String type, String baseVersion, String repositoryUrl, boolean skipDownstreamTriggers, String extension, String classifier) { - LOGGER.log(Level.INFO, "recordGeneratedArtifact({0}#{1}, {2}:{3}:{4}:{5}, version:{6}, repositoryUrl:{7}, skipDownstreamTriggers:{8})", + LOGGER.log(Level.FINEST, "NOT recordGeneratedArtifact({0}#{1}, {2}:{3}:{4}:{5}, version:{6}, repositoryUrl:{7}, skipDownstreamTriggers:{8})", new Object[]{jobFullName, buildNumber, groupId, artifactId, baseVersion, type, version, repositoryUrl, skipDownstreamTriggers}); } @Override public void recordBuildUpstreamCause(String upstreamJobName, int upstreamBuildNumber, String downstreamJobName, int downstreamBuildNumber) { - LOGGER.log(Level.INFO, "recordBuildUpstreamCause(upstreamBuild: {0}#{1}, downstreamBuild: {2}#{3})", + LOGGER.log(Level.FINEST, "NOT recordBuildUpstreamCause(upstreamBuild: {0}#{1}, downstreamBuild: {2}#{3})", new Object[]{upstreamJobName, upstreamBuildNumber, downstreamJobName, downstreamBuildNumber}); } @Override public void renameJob(String oldFullName, String newFullName) { - LOGGER.log(Level.INFO, "renameJob({0}, {1})", new Object[]{oldFullName, newFullName}); + LOGGER.log(Level.FINEST, "NOT renameJob({0}, {1})", new Object[]{oldFullName, newFullName}); } @Override public void deleteJob(String jobFullName) { - LOGGER.log(Level.INFO, "deleteJob({0})", new Object[]{jobFullName}); + LOGGER.log(Level.FINEST, "NOT deleteJob({0})", new Object[]{jobFullName}); } @Override public void deleteBuild(String jobFullName, int buildNumber) { - LOGGER.log(Level.INFO, "deleteBuild({0}#{1})", new Object[]{jobFullName, buildNumber}); + LOGGER.log(Level.FINEST, "NOT deleteBuild({0}#{1})", new Object[]{jobFullName, buildNumber}); } @@ -133,7 +157,7 @@ public Map listTransitiveUpstreamJobs(String jobFullName, int b @Override public void cleanup() { - LOGGER.log(Level.INFO, "cleanup()"); + LOGGER.log(Level.FINEST, "cleanup()"); } @NonNull @@ -144,7 +168,7 @@ public List getGeneratedArtifacts(@NonNull String jobFullName, in @Override public void updateBuildOnCompletion(@NonNull String jobFullName, int buildNumber, int buildResultOrdinal, long startTimeInMillis, long durationInMillis) { - LOGGER.log(Level.INFO, "updateBuildOnCompletion({0}, {1}, result: {2}, startTime): {3}, duration: {4}", + LOGGER.log(Level.FINEST, "NOOT updateBuildOnCompletion({0}, {1}, result: {2}, startTime): {3}, duration: {4}", new Object[]{jobFullName, buildNumber, buildResultOrdinal, startTimeInMillis, durationInMillis}); } diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/UpstreamMemory.java b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/UpstreamMemory.java similarity index 84% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/UpstreamMemory.java rename to pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/UpstreamMemory.java index f8b6c6b3..2d18f963 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/UpstreamMemory.java +++ b/pipeline-maven-api/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/UpstreamMemory.java @@ -1,7 +1,5 @@ package org.jenkinsci.plugins.pipeline.maven.dao; -import static org.jenkinsci.plugins.pipeline.maven.dao.MonitoringPipelineMavenPluginDaoDecorator.registerCacheStatsSupplier; - import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -22,7 +20,7 @@ public class UpstreamMemory { private static final AtomicInteger MISSES = new AtomicInteger(); static { - registerCacheStatsSupplier(() -> new CacheStats("listUpstreamJobs", HITS.get(), MISSES.get())); + MonitoringPipelineMavenPluginDaoDecorator.registerCacheStatsSupplier(() -> new CacheStats("listUpstreamJobs", HITS.get(), MISSES.get())); } // remember the already known upstreams diff --git a/pipeline-maven-api/src/main/resources/index.jelly b/pipeline-maven-api/src/main/resources/index.jelly new file mode 100644 index 00000000..498a4bf0 --- /dev/null +++ b/pipeline-maven-api/src/main/resources/index.jelly @@ -0,0 +1,4 @@ + +
+ Pipeline Maven Plugin API +
diff --git a/pipeline-maven-api/src/main/resources/org/jenkinsci/plugins/pipeline/maven/dao/Messages.properties b/pipeline-maven-api/src/main/resources/org/jenkinsci/plugins/pipeline/maven/dao/Messages.properties new file mode 100644 index 00000000..b673d168 --- /dev/null +++ b/pipeline-maven-api/src/main/resources/org/jenkinsci/plugins/pipeline/maven/dao/Messages.properties @@ -0,0 +1 @@ +dao.null.description=Pipeline Maven Plugin no storage mode \ No newline at end of file diff --git a/pipeline-maven-database/pom.xml b/pipeline-maven-database/pom.xml new file mode 100644 index 00000000..12763d5c --- /dev/null +++ b/pipeline-maven-database/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + org.jenkins-ci.plugins + pipeline-maven-parent + ${changelist} + + pipeline-maven-database + Pipeline Maven Plugin Database + hpi + + + + org.jenkins-ci.plugins + pipeline-maven-api + + + org.jenkins-ci.plugins + credentials + + + com.zaxxer + HikariCP + ${hikaricp.version} + + + org.slf4j + slf4j-api + + + + + io.jenkins.plugins + h2-api + ${jenkins-plugin-h2.version} + true + + + io.jenkins.plugins + mysql-api + ${jenkins-plugin-mysql.version} + true + + + com.google.protobuf + protobuf-java + + + + + io.jenkins.plugins + postgresql-api + ${jenkins-plugin-postgresql.version} + true + + + org.slf4j + slf4j-simple + + + org.testcontainers + junit-jupiter + test + + + org.testcontainers + mysql + test + + + org.testcontainers + postgresql + test + + + org.testcontainers + testcontainers + test + + + + + diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDao.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/AbstractPipelineMavenPluginDao.java similarity index 76% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDao.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/AbstractPipelineMavenPluginDao.java index 390cdff6..d0c85ef7 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/AbstractPipelineMavenPluginDao.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/AbstractPipelineMavenPluginDao.java @@ -22,20 +22,32 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; - +package org.jenkinsci.plugins.pipeline.maven.db; + +import com.cloudbees.plugins.credentials.CredentialsMatchers; +import com.cloudbees.plugins.credentials.CredentialsProvider; +import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.ExtensionList; import hudson.model.Item; import hudson.model.Result; import hudson.model.Run; +import hudson.security.ACL; +import hudson.util.FormValidation; +import hudson.util.Secret; +import jenkins.model.Jenkins; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.h2.api.ErrorCode; import org.jenkinsci.plugins.pipeline.maven.MavenArtifact; import org.jenkinsci.plugins.pipeline.maven.MavenDependency; +import org.jenkinsci.plugins.pipeline.maven.dao.*; import org.jenkinsci.plugins.pipeline.maven.db.migration.MigrationStep; -import org.jenkinsci.plugins.pipeline.maven.util.ClassUtils; -import org.jenkinsci.plugins.pipeline.maven.util.RuntimeIoException; -import org.jenkinsci.plugins.pipeline.maven.util.RuntimeSqlException; +import org.jenkinsci.plugins.pipeline.maven.db.util.ClassUtils; +import org.jenkinsci.plugins.pipeline.maven.db.util.RuntimeIoException; +import org.jenkinsci.plugins.pipeline.maven.db.util.RuntimeSqlException; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -43,9 +55,11 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; +import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.DatabaseMetaData; +import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -53,17 +67,8 @@ import java.sql.Timestamp; import java.text.DecimalFormat; import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Objects; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; @@ -81,16 +86,344 @@ public abstract class AbstractPipelineMavenPluginDao implements PipelineMavenPlu @Nullable private transient Long jenkinsMasterPrimaryKey; - public AbstractPipelineMavenPluginDao(@NonNull DataSource ds) { - ds.getClass(); // check non null + @SuppressFBWarnings("NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR") + protected AbstractPipelineMavenPluginDao() { + // this one is here only to help when using Extension.lookup + } + public AbstractPipelineMavenPluginDao(@NonNull DataSource ds) { + Objects.requireNonNull(ds, "Datasource cannot be null"); this.ds = ds; - registerJdbcDriver(); initializeDatabase(); testDatabase(); } + protected boolean acceptNoCredentials() { + return false; + } + + private class JDBCDaoBuilder implements Builder { + protected final Logger LOGGER = Logger.getLogger(JDBCDaoBuilder.class.getName()); + + private final Class pipelineMavenPluginDaoClass; + + public JDBCDaoBuilder(Class pipelineMavenPluginDaoClass) { + this.pipelineMavenPluginDaoClass = pipelineMavenPluginDaoClass; + } + + @Override + public PipelineMavenPluginDao build(Config config) { + Jenkins j = Jenkins.get(); + PipelineMavenPluginDao dao; + try { + String jdbcUrl = config.getJdbcUrl(); + if(StringUtils.isBlank(jdbcUrl)) { + // some dao such h2 can use default jdbc ur + Optional optionalPipelineMavenPluginDao = + ExtensionList.lookup(PipelineMavenPluginDao.class) + .stream() + .filter(pipelineMavenPluginDao -> pipelineMavenPluginDao.getClass().getName().equals(pipelineMavenPluginDaoClass.getName())) + .findFirst(); + if(optionalPipelineMavenPluginDao.isPresent()){ + jdbcUrl = optionalPipelineMavenPluginDao.get().getDefaultJdbcUrl(); + } + } + String jdbcUserName, jdbcPassword; + + if (StringUtils.isBlank(config.getCredentialsId()) && !AbstractPipelineMavenPluginDao.this.acceptNoCredentials()) + throw new IllegalStateException("No credentials defined for JDBC URL '" + jdbcUrl + "'"); + + UsernamePasswordCredentials jdbcCredentials = null; + if (!StringUtils.isBlank(config.getCredentialsId())) { + jdbcCredentials = (UsernamePasswordCredentials) CredentialsMatchers.firstOrNull( + CredentialsProvider.lookupCredentials(UsernamePasswordCredentials.class, j, + ACL.SYSTEM, Collections.EMPTY_LIST), + CredentialsMatchers.withId(config.getCredentialsId())); + } + + if (jdbcCredentials == null && pipelineMavenPluginDaoClass == PipelineMavenPluginH2Dao.class) { + jdbcUserName = "sa"; + jdbcPassword = "sa"; + } + else if (jdbcCredentials == null) { + throw new IllegalStateException("Credentials '" + config.getCredentialsId() + "' defined for JDBC URL '" + jdbcUrl + "' NOT found"); + } + else { + jdbcUserName = jdbcCredentials.getUsername(); + jdbcPassword = Secret.toString(jdbcCredentials.getPassword()); + } + + HikariConfig dsConfig = createHikariConfig(config.getProperties(), jdbcUrl, jdbcUserName, jdbcPassword); + dsConfig.setAutoCommit(false); + + // TODO cleanup this quick fix for JENKINS-54587, we should have a better solution with the JDBC driver loaded by the DAO itself + try { + DriverManager.getDriver(jdbcUrl); + } catch (SQLException e) { + if ("08001".equals(e.getSQLState()) && 0 == e.getErrorCode()) { + // if it's a "No suitable driver" exception, we try to load the jdbc driver and retry + if (jdbcUrl.startsWith("jdbc:h2:")) { + try { + Class.forName("org.h2.Driver"); + } catch (ClassNotFoundException cnfe) { + throw new IllegalStateException("H2 driver should be bundled with this plugin"); + } + } else if (jdbcUrl.startsWith("jdbc:mysql:")) { + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException cnfe) { + throw new RuntimeException("MySql driver 'com.mysql.cj.jdbc.Driver' not found. Please install the 'MySQL Database Plugin' to install the MySql driver"); + } + } else if (jdbcUrl.startsWith("jdbc:postgresql:")) { + try { + Class.forName("org.postgresql.Driver"); + } catch (ClassNotFoundException cnfe) { + throw new RuntimeException("PostgreSQL driver 'org.postgresql.Driver' not found. Please install the 'PostgreSQL Database Plugin' to install the PostgreSQL driver"); + } + } else { + throw new IllegalArgumentException("Unsupported database type in JDBC URL " + jdbcUrl); + } + DriverManager.getDriver(jdbcUrl); + } else { + throw e; + } + } + + LOGGER.log(Level.INFO, "Connect to database {0} with username {1}", new Object[]{jdbcUrl, jdbcUserName}); + DataSource ds = new HikariDataSource(dsConfig); + + try { + dao = new MonitoringPipelineMavenPluginDaoDecorator( + new CustomTypePipelineMavenPluginDaoDecorator((PipelineMavenPluginDao)pipelineMavenPluginDaoClass + .getConstructor(DataSource.class) + .newInstance(ds))); + } catch (Exception e) { + throw new SQLException( + "Exception connecting to '" + jdbcUrl + "' with credentials '" + config.getCredentialsId() + "' (" + + jdbcUserName + "/***) and DAO " + getClass().getSimpleName(), e); + } + } catch (RuntimeException | SQLException e) { + LOGGER.log(Level.WARNING, "Exception creating database dao, skip", e); + dao = new PipelineMavenPluginNullDao(); + } + return dao; + } + + @Override + public FormValidation validateConfiguration(Config config) { + String jdbcUrl = config.getJdbcUrl(); + if (StringUtils.isBlank(jdbcUrl)) { + return FormValidation.ok(); + } + + String driverClass = null; + try { + if (StringUtils.isBlank(jdbcUrl)) { + driverClass = "org.h2.Driver"; + } else if (jdbcUrl.startsWith("jdbc:h2")) { + driverClass = "org.h2.Driver"; + } else if (jdbcUrl.startsWith("jdbc:mysql")) { + driverClass = "com.mysql.cj.jdbc.Driver"; + } else if (jdbcUrl.startsWith("jdbc:postgresql:")) { + driverClass = "org.postgresql.Driver"; + } else { + return FormValidation.error("Unsupported database specified in JDBC url '" + jdbcUrl + "'"); + } + try { + Class.forName(driverClass); + } catch (ClassNotFoundException e) { + if ("com.mysql.cj.jdbc.Driver".equals(driverClass)) { + return FormValidation.error("MySQL JDBC driver '" + driverClass + "' not found, please install the Jenkins 'MySQL API Plugin'", e); + } else if ("org.postgresql.Driver".equals(driverClass)) { + return FormValidation.error("PostgreSQL JDBC driver '" + driverClass + "' not found, please install the Jenkins 'PostgreSQL API Plugin'" + jdbcUrl, e); + } else { + throw e; + } + } + + String jdbcCredentialsId = config.getCredentialsId(); + + String jdbcUserName, jdbcPassword; + if (StringUtils.isEmpty(jdbcCredentialsId)) { + if (AbstractPipelineMavenPluginDao.this.acceptNoCredentials()) { + // embedded database, assume OK + return FormValidation.ok(); + } else { + return FormValidation.error("No credentials specified for JDBC url '" + jdbcUrl + "'"); + } + } else { + UsernamePasswordCredentials jdbcCredentials = (UsernamePasswordCredentials) CredentialsMatchers.firstOrNull( + CredentialsProvider.lookupCredentials(UsernamePasswordCredentials.class, Jenkins.get(), + ACL.SYSTEM, Collections.EMPTY_LIST), + CredentialsMatchers.withId(jdbcCredentialsId)); + if (jdbcCredentials == null) { + return FormValidation.error("Credentials '" + jdbcCredentialsId + "' defined for JDBC URL '" + jdbcUrl + "' not found"); + } + jdbcUserName = jdbcCredentials.getUsername(); + jdbcPassword = Secret.toString(jdbcCredentials.getPassword()); + } + + HikariConfig dsConfig = createHikariConfig(config.getProperties(), jdbcUrl, jdbcUserName, jdbcPassword); + + try (HikariDataSource ds = new HikariDataSource(dsConfig)) { + try (Connection cnn = ds.getConnection()) { + DatabaseMetaData metaData = cnn.getMetaData(); + // getDatabaseProductVersion(): + // * MySQL: "8.0.13" + // * Amazon Aurora: "5.6.10" + // * MariaDB: "5.5.5-10.2.20-MariaDB", "5.5.5-10.3.11-MariaDB-1:10.3.11+maria~bionic" + String databaseVersionDescription = metaData.getDatabaseProductName() + " " + metaData.getDatabaseProductVersion(); + String databaseRequirement = "MySQL Server version 5.7+ or Amazon Aurora MySQL 5.6+ or MariaDB 10.2+ or PostgreSQL 10+ is required"; + if ("MySQL".equals(metaData.getDatabaseProductName())) { + @Nullable + String amazonAuroraVersion; + try (Statement stmt = cnn.createStatement()) { + try (ResultSet rst = stmt.executeQuery("select AURORA_VERSION()")) { + rst.next(); + amazonAuroraVersion = rst.getString(1); + databaseVersionDescription += " / Aurora " + rst.getString(1); + } catch (SQLException e) { + if (e.getErrorCode() == 1305) { // com.mysql.cj.exceptions.MysqlErrorNumbers.ER_SP_DOES_NOT_EXIST + amazonAuroraVersion = null; + } else { + LOGGER.log(Level.WARNING,"Exception checking Amazon Aurora version", e); + amazonAuroraVersion = null; + } + } + } + @Nullable + String mariaDbVersion = PipelineMavenPluginMySqlDao.extractMariaDbVersion(metaData.getDatabaseProductVersion()); + + switch (metaData.getDatabaseMajorVersion()) { + case 8: + // OK + break; + case 5: + switch (metaData.getDatabaseMinorVersion()) { + case 7: + // ok + break; + case 6: + if (amazonAuroraVersion == null) { + // see JENKINS-54784 + return FormValidation.warning("Non validated MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); + } else { + // we have successfully tested on Amazon Aurora MySQL 5.6.10a + break; + } + case 5: + if (mariaDbVersion == null) { + return FormValidation.warning("Non validated MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); + } else { + // JENKINS-55378 have successfully tested with "5.5.5-10.2.20-MariaDB" + return FormValidation.ok("MariaDB version " + mariaDbVersion + " detected. Please ensure that your MariaDB version is at least version 10.2+"); + } + default: + return FormValidation.error("Non supported MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); + } + break; + default: + return FormValidation.error("Non supported MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); + } + } else if ("PostgreSQL".equals(metaData.getDatabaseProductName())) { + @Nullable + String amazonAuroraVersion; // https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Updates.html + try (Statement stmt = cnn.createStatement()) { + try (ResultSet rst = stmt.executeQuery("select AURORA_VERSION()")) { + rst.next(); + amazonAuroraVersion = rst.getString(1); + databaseVersionDescription += " / Aurora " + rst.getString(1); + } catch (SQLException e) { + if ("42883".equals(e.getSQLState())) { // org.postgresql.util.PSQLState.UNDEFINED_FUNCTION.getState() + amazonAuroraVersion = null; + } else { + LOGGER.log(Level.WARNING,"Exception checking Amazon Aurora version", e); + amazonAuroraVersion = null; + } + } + } + switch (metaData.getDatabaseMajorVersion()) { + case 14: + case 13: + case 12: + case 11: + case 10: + case 9: + case 8: + // OK + break; + default: + return FormValidation.warning("Non tested PostgreSQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); + } + } else { + return FormValidation.warning("Non production grade database. For production workloads, " + databaseRequirement); + } + try (Statement stmt = cnn.createStatement()) { + try (ResultSet rst = stmt.executeQuery("select 1")) { + rst.next(); + // TODO more tests + } + } + return FormValidation.ok(databaseVersionDescription + " is a supported database"); + } catch (SQLException e ){ + return FormValidation.error(e, "Failure to connect to the database " + jdbcUrl); + } + } + } catch (RuntimeException e) { + return FormValidation.error(e, "Failed to test JDBC connection '" + jdbcUrl + "'"); + } catch (ClassNotFoundException e) { + return FormValidation.error(e, "Failed to load JDBC driver '" + driverClass + "' for JDBC connection '" + jdbcUrl + "'"); + } + } + } + + @Override + public Builder getBuilder() { + return new JDBCDaoBuilder(getClass()); + } + + private static HikariConfig createHikariConfig(String properties, String jdbcUrl, String jdbcUserName, String jdbcPassword) { + Properties p = new Properties(); + // todo refactor the DAO to inject config defaults in the DAO + if (jdbcUrl.startsWith("jdbc:mysql")) { + // https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby + // https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration + p.setProperty("dataSource.cachePrepStmts", "true"); + p.setProperty("dataSource.prepStmtCacheSize", "250"); + p.setProperty("dataSource.prepStmtCacheSqlLimit", "2048"); + p.setProperty("dataSource.useServerPrepStmts", "true"); + p.setProperty("dataSource.useLocalSessionState", "true"); + p.setProperty("dataSource.rewriteBatchedStatements", "true"); + p.setProperty("dataSource.cacheResultSetMetadata", "true"); + p.setProperty("dataSource.cacheServerConfiguration", "true"); + p.setProperty("dataSource.elideSetAutoCommits", "true"); + p.setProperty("dataSource.maintainTimeStats", "false"); + } else if (jdbcUrl.startsWith("jdbc:postgresql")) { + // no tuning recommendations found for postgresql + } else if (jdbcUrl.startsWith("jdbc:h2")) { + // dsConfig.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); don't specify the datasource due to a classloading issue + } else { + // unsupported config + } + + if (StringUtils.isNotBlank(properties)) { + try { + p.load(new StringReader(properties)); + } catch (IOException e) { + throw new IllegalStateException("Failed to read properties.", e); + } + } + Logger.getLogger(AbstractPipelineMavenPluginDao.class.getName()).log(Level.INFO, "Applied pool properties {0}", p); + HikariConfig dsConfig = new HikariConfig(p); + dsConfig.setJdbcUrl(jdbcUrl); + dsConfig.setUsername(jdbcUserName); + dsConfig.setPassword(jdbcPassword); + // to mimic the old behaviour pre JENKINS-69375 fix + dsConfig.setDataSourceProperties(p); + return dsConfig; + } + protected abstract void registerJdbcDriver(); @Override diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2Dao.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2Dao.java similarity index 84% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2Dao.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2Dao.java index 0d35deb5..5f63879f 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2Dao.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2Dao.java @@ -22,11 +22,14 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; +import hudson.Extension; +import jenkins.model.Jenkins; import org.h2.jdbcx.JdbcConnectionPool; import edu.umd.cs.findbugs.annotations.NonNull; + import javax.sql.DataSource; import java.io.File; import java.io.IOException; @@ -39,17 +42,33 @@ /** * @author Cyrille Le Clerc */ +@Extension public class PipelineMavenPluginH2Dao extends AbstractPipelineMavenPluginDao { + public PipelineMavenPluginH2Dao() { + super(); + } + public PipelineMavenPluginH2Dao(@NonNull DataSource ds) { super(ds); } + protected boolean acceptNoCredentials() { + return true; + } + + @Override + public String getDescription() { + return Messages.dao_h2_description(); + } + public PipelineMavenPluginH2Dao(@NonNull File rootDir) { this(JdbcConnectionPool.create("jdbc:h2:file:" + new File(rootDir, "jenkins-jobs").getAbsolutePath() + ";" + "AUTO_SERVER=TRUE;MULTI_THREADED=1;QUERY_CACHE_SIZE=25;JMX=TRUE", "sa", "sa")); } + + @Override protected void registerJdbcDriver() { try { @@ -122,4 +141,17 @@ public void close() throws IOException { } super.close(); } + + public String getDefaultJdbcUrl() { + File databaseRootDir = new File(Jenkins.get().getRootDir(), "jenkins-jobs"); + if (!databaseRootDir.exists()) { + boolean created = databaseRootDir.mkdirs(); + if (!created) { + throw new IllegalStateException("Failure to create database root dir " + databaseRootDir); + } + } + return "jdbc:h2:file:" + new File(databaseRootDir, "jenkins-jobs").getAbsolutePath() + ";" + + "AUTO_SERVER=TRUE;MULTI_THREADED=1;QUERY_CACHE_SIZE=25;JMX=TRUE"; + } + } diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDao.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDao.java similarity index 93% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDao.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDao.java index d1a702fb..2f3e7db6 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDao.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDao.java @@ -22,11 +22,12 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import com.mysql.cj.exceptions.MysqlErrorNumbers; +import hudson.Extension; import org.apache.commons.lang.StringUtils; -import org.jenkinsci.plugins.pipeline.maven.util.RuntimeSqlException; +import org.jenkinsci.plugins.pipeline.maven.db.util.RuntimeSqlException; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -41,8 +42,18 @@ /** * @author Cyrille Le Clerc */ +@Extension public class PipelineMavenPluginMySqlDao extends AbstractPipelineMavenPluginDao { + public PipelineMavenPluginMySqlDao() { + super(); + } + + @Override + public String getDescription() { + return Messages.dao_mysql_description(); + } + /** * Extract the MariaDB server version from {@link DatabaseMetaData#getDatabaseProductVersion()} * diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDao.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDao.java similarity index 93% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDao.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDao.java index be9e2079..130d1798 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDao.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDao.java @@ -22,8 +22,9 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; +import hudson.Extension; import org.postgresql.util.PSQLState; import edu.umd.cs.findbugs.annotations.NonNull; @@ -39,12 +40,23 @@ /** * @author Cyrille Le Clerc */ +@Extension public class PipelineMavenPluginPostgreSqlDao extends AbstractPipelineMavenPluginDao { + public PipelineMavenPluginPostgreSqlDao() { + super(); + } + public PipelineMavenPluginPostgreSqlDao(@NonNull DataSource ds) { super(ds); } + + @Override + public String getDescription() { + return Messages.dao_postgesql_description(); + } + @Override public String getJdbcScheme() { return "postgresql"; diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/MigrationStep.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/MigrationStep.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/MigrationStep.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/MigrationStep.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep10.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep10.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep10.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep10.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep11.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep11.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep11.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep11.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep8.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep8.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep8.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/h2/MigrationStep8.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/mysql/MigrationStep12.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/mysql/MigrationStep12.java similarity index 100% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/mysql/MigrationStep12.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/migration/mysql/MigrationStep12.java diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/ClassUtils.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/ClassUtils.java similarity index 91% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/ClassUtils.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/ClassUtils.java index cb9a541a..deb95b51 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/ClassUtils.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/ClassUtils.java @@ -1,4 +1,4 @@ -package org.jenkinsci.plugins.pipeline.maven.util; +package org.jenkinsci.plugins.pipeline.maven.db.util; import java.io.InputStream; diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/RuntimeIoException.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/RuntimeIoException.java similarity index 93% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/RuntimeIoException.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/RuntimeIoException.java index 52b8ae9d..5a2b0cfd 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/RuntimeIoException.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/RuntimeIoException.java @@ -1,4 +1,4 @@ -package org.jenkinsci.plugins.pipeline.maven.util; +package org.jenkinsci.plugins.pipeline.maven.db.util; /** * We prefer {@link RuntimeException} to catched exceptions. diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/RuntimeSqlException.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/RuntimeSqlException.java similarity index 93% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/RuntimeSqlException.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/RuntimeSqlException.java index ace4550a..495440b6 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/RuntimeSqlException.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/RuntimeSqlException.java @@ -1,4 +1,4 @@ -package org.jenkinsci.plugins.pipeline.maven.util; +package org.jenkinsci.plugins.pipeline.maven.db.util; /** * We prefer {@link RuntimeException} to catched exceptions. diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/SqlUtils.java b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/SqlUtils.java similarity index 92% rename from jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/SqlUtils.java rename to pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/SqlUtils.java index 575ad7ed..de4d1f9e 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/util/SqlUtils.java +++ b/pipeline-maven-database/src/main/java/org/jenkinsci/plugins/pipeline/maven/db/util/SqlUtils.java @@ -1,4 +1,4 @@ -package org.jenkinsci.plugins.pipeline.maven.util; +package org.jenkinsci.plugins.pipeline.maven.db.util; import java.io.PrintStream; import java.sql.ResultSet; diff --git a/pipeline-maven-database/src/main/resources/index.jelly b/pipeline-maven-database/src/main/resources/index.jelly new file mode 100644 index 00000000..498a4bf0 --- /dev/null +++ b/pipeline-maven-database/src/main/resources/index.jelly @@ -0,0 +1,4 @@ + +
+ Pipeline Maven Plugin API +
diff --git a/pipeline-maven-database/src/main/resources/org/jenkinsci/plugins/pipeline/maven/db/Messages.properties b/pipeline-maven-database/src/main/resources/org/jenkinsci/plugins/pipeline/maven/db/Messages.properties new file mode 100644 index 00000000..84559b11 --- /dev/null +++ b/pipeline-maven-database/src/main/resources/org/jenkinsci/plugins/pipeline/maven/db/Messages.properties @@ -0,0 +1,3 @@ +dao.mysql.description=Pipeline Maven Plugin storage using MySql +dao.h2.description=Pipeline Maven Plugin storage using H2 +dao.postgesql.description=Pipeline Maven Plugin storage using Postgres \ No newline at end of file diff --git a/jenkins-plugin/src/main/resources/sql/h2/01_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/01_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/01_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/01_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/02_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/02_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/02_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/02_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/03_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/03_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/03_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/03_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/04_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/04_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/04_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/04_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/05_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/05_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/05_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/05_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/06_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/06_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/06_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/06_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/07_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/07_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/07_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/07_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/08_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/08_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/08_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/08_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/09_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/09_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/09_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/09_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/10_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/10_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/10_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/10_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/11_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/11_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/11_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/11_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/h2/12_migration.sql b/pipeline-maven-database/src/main/resources/sql/h2/12_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/h2/12_migration.sql rename to pipeline-maven-database/src/main/resources/sql/h2/12_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/01_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/01_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/01_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/01_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/02_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/02_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/02_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/02_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/03_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/03_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/03_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/03_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/04_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/04_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/04_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/04_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/05_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/05_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/05_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/05_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/06_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/06_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/06_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/06_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/07_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/07_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/07_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/07_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/08_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/08_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/08_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/08_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/09_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/09_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/09_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/09_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/10_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/10_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/10_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/10_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/11_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/11_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/11_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/11_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/12_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/12_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/12_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/12_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/mysql/13_migration.sql b/pipeline-maven-database/src/main/resources/sql/mysql/13_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/mysql/13_migration.sql rename to pipeline-maven-database/src/main/resources/sql/mysql/13_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/postgresql/01_migration.sql b/pipeline-maven-database/src/main/resources/sql/postgresql/01_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/postgresql/01_migration.sql rename to pipeline-maven-database/src/main/resources/sql/postgresql/01_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/postgresql/02_migration.sql b/pipeline-maven-database/src/main/resources/sql/postgresql/02_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/postgresql/02_migration.sql rename to pipeline-maven-database/src/main/resources/sql/postgresql/02_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/postgresql/03_migration.sql b/pipeline-maven-database/src/main/resources/sql/postgresql/03_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/postgresql/03_migration.sql rename to pipeline-maven-database/src/main/resources/sql/postgresql/03_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/postgresql/04_migration.sql b/pipeline-maven-database/src/main/resources/sql/postgresql/04_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/postgresql/04_migration.sql rename to pipeline-maven-database/src/main/resources/sql/postgresql/04_migration.sql diff --git a/jenkins-plugin/src/main/resources/sql/postgresql/05_migration.sql b/pipeline-maven-database/src/main/resources/sql/postgresql/05_migration.sql similarity index 100% rename from jenkins-plugin/src/main/resources/sql/postgresql/05_migration.sql rename to pipeline-maven-database/src/main/resources/sql/postgresql/05_migration.sql diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDaoAbstractTest.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginDaoAbstractTest.java similarity index 99% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDaoAbstractTest.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginDaoAbstractTest.java index 56f3685c..ef658a1d 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginDaoAbstractTest.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginDaoAbstractTest.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import static org.assertj.core.api.Assertions.assertThat; @@ -37,7 +37,7 @@ import org.jenkinsci.plugins.pipeline.maven.MavenArtifact; import org.jenkinsci.plugins.pipeline.maven.MavenDependency; -import org.jenkinsci.plugins.pipeline.maven.util.SqlTestsUtils; +import org.jenkinsci.plugins.pipeline.maven.db.util.SqlTestsUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2DaoInitializationTest.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2DaoInitializationTest.java similarity index 99% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2DaoInitializationTest.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2DaoInitializationTest.java index 61918516..f39701e6 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2DaoInitializationTest.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2DaoInitializationTest.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import static org.assertj.core.api.Assertions.assertThat; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2DaoTest.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2DaoTest.java similarity index 97% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2DaoTest.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2DaoTest.java index 9283429e..1b02739e 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginH2DaoTest.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginH2DaoTest.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import org.h2.jdbcx.JdbcConnectionPool; import org.jenkinsci.plugins.pipeline.maven.db.migration.MigrationStep; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoIT.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoIT.java similarity index 98% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoIT.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoIT.java index 8f99397a..b552fece 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoIT.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoIT.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import javax.sql.DataSource; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoInitializationTest.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoInitializationTest.java similarity index 99% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoInitializationTest.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoInitializationTest.java index 70d2a80e..ea487def 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoInitializationTest.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoInitializationTest.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import static org.assertj.core.api.Assertions.assertThat; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoTest.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoTest.java similarity index 98% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoTest.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoTest.java index df2978cb..3c998c00 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginMySqlDaoTest.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginMySqlDaoTest.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import static org.assertj.core.api.Assertions.assertThat; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDaoIT.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDaoIT.java similarity index 98% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDaoIT.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDaoIT.java index f1b34bb0..68495341 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDaoIT.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDaoIT.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import javax.sql.DataSource; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDaoTest.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDaoTest.java similarity index 97% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDaoTest.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDaoTest.java index 4efa1ae6..8a3c6015 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/dao/PipelineMavenPluginPostgreSqlDaoTest.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/PipelineMavenPluginPostgreSqlDaoTest.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package org.jenkinsci.plugins.pipeline.maven.dao; +package org.jenkinsci.plugins.pipeline.maven.db; import org.h2.jdbcx.JdbcConnectionPool; import org.jenkinsci.plugins.pipeline.maven.db.migration.MigrationStep; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/util/ClassUtilsTest.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/util/ClassUtilsTest.java similarity index 72% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/util/ClassUtilsTest.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/util/ClassUtilsTest.java index 2580b92a..481fcb6f 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/util/ClassUtilsTest.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/util/ClassUtilsTest.java @@ -1,7 +1,7 @@ -package org.jenkinsci.plugins.pipeline.maven.util; +package org.jenkinsci.plugins.pipeline.maven.db.util; import static org.assertj.core.api.Assertions.assertThat; -import static org.jenkinsci.plugins.pipeline.maven.util.ClassUtils.getResourceAsStream; +import static org.jenkinsci.plugins.pipeline.maven.db.util.ClassUtils.getResourceAsStream; import org.junit.jupiter.api.Test; diff --git a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/util/SqlTestsUtils.java b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/util/SqlTestsUtils.java similarity index 96% rename from jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/util/SqlTestsUtils.java rename to pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/util/SqlTestsUtils.java index 8b23fdf6..2c5734bd 100644 --- a/jenkins-plugin/src/test/java/org/jenkinsci/plugins/pipeline/maven/util/SqlTestsUtils.java +++ b/pipeline-maven-database/src/test/java/org/jenkinsci/plugins/pipeline/maven/db/util/SqlTestsUtils.java @@ -1,8 +1,10 @@ -package org.jenkinsci.plugins.pipeline.maven.util; +package org.jenkinsci.plugins.pipeline.maven.db.util; import org.h2.api.ErrorCode; import edu.umd.cs.findbugs.annotations.NonNull; +import org.jenkinsci.plugins.pipeline.maven.db.util.RuntimeSqlException; + import javax.sql.DataSource; import static java.util.Optional.ofNullable; diff --git a/jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/util/classutils-test-1.txt b/pipeline-maven-database/src/test/resources/org/jenkinsci/plugins/pipeline/maven/util/classutils-test-1.txt similarity index 100% rename from jenkins-plugin/src/test/resources/org/jenkinsci/plugins/pipeline/maven/util/classutils-test-1.txt rename to pipeline-maven-database/src/test/resources/org/jenkinsci/plugins/pipeline/maven/util/classutils-test-1.txt diff --git a/pom.xml b/pom.xml index c97d6be3..febc6fa5 100644 --- a/pom.xml +++ b/pom.xml @@ -72,6 +72,8 @@ + pipeline-maven-api + pipeline-maven-database maven-spy jenkins-plugin @@ -102,9 +104,10 @@ 2102.v854b_fec19c92 2.361.4 5.10.0 - 1.4.11 + 3.3.9 0.3.5 3.3.0 + 3.4.2 3.8.8 3.5.1 2.0.7 @@ -114,6 +117,34 @@ + io.jenkins.tools.bom + bom-2.361.x + ${jenkins-tools-bom.version} + pom + import + + + + + + + org.apache.maven + maven-artifact + ${maven.version} + + + org.apache.maven + maven-core + ${maven-compat.version} + + + org.codehaus.plexus + plexus-utils + ${plexus-utils.version} + + org.junit junit-bom ${junit.version} @@ -126,13 +157,32 @@ slf4j-api ${slf4j.version} + + org.slf4j + slf4j-simple + ${slf4j.version} + + + org.jenkins-ci.plugins + pipeline-maven-api + ${project.version} + org.assertj assertj-core ${assertj.version} test + + + org.testcontainers + testcontainers-bom + ${testcontainers.version} + pom + import + +

sS7#8dVdZ@0>m=!C)5e;b;%VzQ( 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 https://github.com/jenkinsci/pipeline-maven-plugin/releases + 1333 - - - - io.jenkins.tools.bom - bom-2.361.x - ${jenkins-tools-bom.version} - pom - import - - - - - - com.google.code.gson - gson - ${gson.version} - - - org.codehaus.plexus - plexus-utils - ${plexus-utils.version} - - - org.fusesource.jansi - jansi - ${jansi.version} - - - - com.zaxxer - HikariCP - ${hikaricp.version} - - - org.slf4j - slf4j-api - - + org.jenkins-ci.plugins + pipeline-maven-api + + + + + org.jenkins-ci.plugins + pipeline-maven-database + ${project.version} + test io.jenkins.plugins h2-api ${jenkins-plugin-h2.version} + test io.jenkins.plugins mysql-api ${jenkins-plugin-mysql.version} - true + test com.google.protobuf @@ -105,7 +80,7 @@ io.jenkins.plugins postgresql-api ${jenkins-plugin-postgresql.version} - true + test org.jenkins-ci.main @@ -334,10 +309,8 @@ true - ch.qos.logback - logback-classic - ${logback.version} - test + org.slf4j + slf4j-simple @@ -455,25 +428,21 @@ org.testcontainers junit-jupiter - ${testcontainers.version} test org.testcontainers mysql - ${testcontainers.version} test org.testcontainers postgresql - ${testcontainers.version} test org.testcontainers testcontainers - ${testcontainers.version} test diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig.java b/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig.java index 62f8882b..a3ebed0c 100644 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig.java +++ b/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig.java @@ -28,15 +28,13 @@ import com.cloudbees.plugins.credentials.CredentialsProvider; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; import hudson.Extension; +import hudson.ExtensionList; import hudson.init.Terminator; import hudson.model.Result; import hudson.security.ACL; import hudson.util.FormValidation; import hudson.util.ListBoxModel; -import hudson.util.Secret; import jenkins.model.GlobalConfiguration; import jenkins.model.GlobalConfigurationCategory; import jenkins.model.Jenkins; @@ -44,13 +42,8 @@ import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.jenkinsci.Symbol; -import org.jenkinsci.plugins.pipeline.maven.dao.CustomTypePipelineMavenPluginDaoDecorator; -import org.jenkinsci.plugins.pipeline.maven.dao.MonitoringPipelineMavenPluginDaoDecorator; import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginDao; -import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginH2Dao; -import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginMySqlDao; import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginNullDao; -import org.jenkinsci.plugins.pipeline.maven.dao.PipelineMavenPluginPostgreSqlDao; import org.jenkinsci.plugins.pipeline.maven.service.PipelineTriggerService; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.DataBoundSetter; @@ -61,21 +54,12 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import javax.sql.DataSource; -import java.io.File; import java.io.IOException; -import java.io.StringReader; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; -import java.util.Properties; +import java.util.Optional; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -105,11 +89,33 @@ public class GlobalPipelineMavenConfig extends GlobalConfiguration { private String jdbcCredentialsId; private String properties; + private String daoClass; + @DataBoundConstructor public GlobalPipelineMavenConfig() { load(); } + public List getPipelineMavenPluginDaos() { + return ExtensionList.lookup(PipelineMavenPluginDao.class); + } + + public String getDaoClass() { + return daoClass; + } + + @DataBoundSetter + public void setDaoClass(String daoClass) { + this.daoClass = daoClass; + } + + private Optional findDaoFromExtension(String daoClass) { + return ExtensionList.lookup(PipelineMavenPluginDao.class) + .stream() + .filter(pipelineMavenPluginDao -> StringUtils.equals(pipelineMavenPluginDao.getClass().getName(), daoClass)) + .findFirst(); + } + @Override public ToolConfigurationCategory getCategory() { return GlobalConfigurationCategory.get(ToolConfigurationCategory.class); @@ -221,6 +227,10 @@ public synchronized void setJdbcCredentialsId(String jdbcCredentialsId) { @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException { + if(!StringUtils.equals(json.getString("daoClass"), daoClass)) { + closeDatasource(); + this.dao = null; + } req.bindJSON(this, json); // stapler oddity, empty lists coming from the HTTP request are not set on bean by "req.bindJSON(this, json)" this.publisherOptions = req.bindJSONToList(MavenPublisher.class, json.get("publisherOptions")); @@ -228,113 +238,33 @@ public boolean configure(StaplerRequest req, JSONObject json) throws FormExcepti return true; } - boolean isDaoInitialized() { - return dao != null; + public String getDaoPrettyString() { + return dao != null ? dao.toPrettyString() : "Dao Not Ready yet"; } @NonNull public synchronized PipelineMavenPluginDao getDao() { + if (dao != null) { + return dao; + } Jenkins j = Jenkins.getInstanceOrNull(); if (j == null) { throw new IllegalStateException("Request to get DAO whilst Jenkins is shutting down or starting up"); } else if (j.isTerminating()) { throw new IllegalStateException("Request to get DAO whilst Jenkins is terminating"); } - if (dao == null) { - try { - String jdbcUrl, jdbcUserName, jdbcPassword; - if (StringUtils.isBlank(this.jdbcUrl)) { - // default embedded H2 database - File databaseRootDir = new File(j.getRootDir(), "jenkins-jobs"); - if (!databaseRootDir.exists()) { - boolean created = databaseRootDir.mkdirs(); - if (!created) { - throw new IllegalStateException("Failure to create database root dir " + databaseRootDir); - } - } - jdbcUrl = "jdbc:h2:file:" + new File(databaseRootDir, "jenkins-jobs").getAbsolutePath() + ";" + - "AUTO_SERVER=TRUE;MULTI_THREADED=1;QUERY_CACHE_SIZE=25;JMX=TRUE"; - jdbcUserName = "sa"; - jdbcPassword = "sa"; - } else { - jdbcUrl = this.jdbcUrl; - if (this.jdbcCredentialsId == null) - throw new IllegalStateException("No credentials defined for JDBC URL '" + jdbcUrl + "'"); - - UsernamePasswordCredentials jdbcCredentials = (UsernamePasswordCredentials) CredentialsMatchers.firstOrNull( - CredentialsProvider.lookupCredentials(UsernamePasswordCredentials.class, j, - ACL.SYSTEM, Collections.EMPTY_LIST), - CredentialsMatchers.withId(this.jdbcCredentialsId)); - if (jdbcCredentials == null) { - throw new IllegalStateException("Credentials '" + jdbcCredentialsId + "' defined for JDBC URL '" + jdbcUrl + "' NOT found"); - } - jdbcUserName = jdbcCredentials.getUsername(); - jdbcPassword = Secret.toString(jdbcCredentials.getPassword()); - } - - HikariConfig dsConfig = createHikariConfig(properties, jdbcUrl, jdbcUserName, jdbcPassword); - dsConfig.setAutoCommit(false); - - // TODO cleanup this quick fix for JENKINS-54587, we should have a better solution with the JDBC driver loaded by the DAO itself - try { - DriverManager.getDriver(jdbcUrl); - } catch (SQLException e) { - if ("08001".equals(e.getSQLState()) && 0 == e.getErrorCode()) { - // if it's a "No suitable driver" exception, we try to load the jdbc driver and retry - if (jdbcUrl.startsWith("jdbc:h2:")) { - try { - Class.forName("org.h2.Driver"); - } catch (ClassNotFoundException cnfe) { - throw new IllegalStateException("H2 driver should be bundled with this plugin"); - } - } else if (jdbcUrl.startsWith("jdbc:mysql:")) { - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException cnfe) { - throw new RuntimeException("MySql driver 'com.mysql.cj.jdbc.Driver' not found. Please install the 'MySQL Database Plugin' to install the MySql driver"); - } - } else if (jdbcUrl.startsWith("jdbc:postgresql:")) { - try { - Class.forName("org.postgresql.Driver"); - } catch (ClassNotFoundException cnfe) { - throw new RuntimeException("PostgreSQL driver 'org.postgresql.Driver' not found. Please install the 'PostgreSQL Database Plugin' to install the PostgreSQL driver"); - } - } else { - throw new IllegalArgumentException("Unsupported database type in JDBC URL " + jdbcUrl); - } - DriverManager.getDriver(jdbcUrl); - } else { - throw e; - } - } - - LOGGER.log(Level.INFO, "Connect to database {0} with username {1}", new Object[]{jdbcUrl, jdbcUserName}); - DataSource ds = new HikariDataSource(dsConfig); - - Class daoClass; - if (jdbcUrl.startsWith("jdbc:h2:")) { - daoClass = PipelineMavenPluginH2Dao.class; - } else if (jdbcUrl.startsWith("jdbc:mysql:")) { - daoClass = PipelineMavenPluginMySqlDao.class; - } else if (jdbcUrl.startsWith("jdbc:postgresql:")) { - daoClass = PipelineMavenPluginPostgreSqlDao.class; - } else { - throw new IllegalArgumentException("Unsupported database type in JDBC URL " + jdbcUrl); - } - try { - dao = new MonitoringPipelineMavenPluginDaoDecorator(new CustomTypePipelineMavenPluginDaoDecorator(daoClass.getConstructor(DataSource.class).newInstance(ds))); - } catch (Exception e) { - throw new SQLException( - "Exception connecting to '" + this.jdbcUrl + "' with credentials '" + this.jdbcCredentialsId + "' (" + - jdbcUserName + "/***) and DAO " + daoClass.getSimpleName(), e); - } - - - } catch (RuntimeException | SQLException e) { - LOGGER.log(Level.WARNING, "Exception creating database dao, skip", e); - dao = new PipelineMavenPluginNullDao(); - } + Optional optionalPipelineMavenPluginDao = findDaoFromExtension(getDaoClass()); + if (optionalPipelineMavenPluginDao.isPresent()) { + PipelineMavenPluginDao.Builder.Config config = new PipelineMavenPluginDao.Builder.Config() + .credentialsId(jdbcCredentialsId) + .jdbcUrl(jdbcUrl) + .properties(properties); + this.dao = optionalPipelineMavenPluginDao.get().getBuilder().build(config); + } else { + LOGGER.info("cannot configure any dao so use the default null values one"); + this.dao = new PipelineMavenPluginNullDao(); } + return dao; } @@ -386,210 +316,27 @@ public ListBoxModel doFillJdbcCredentialsIdItems() { public FormValidation doValidateJdbcConnection( @QueryParameter String jdbcUrl, @QueryParameter String properties, - @QueryParameter String jdbcCredentialsId) { + @QueryParameter String jdbcCredentialsId, + @QueryParameter String daoClass) { Jenkins.get().checkPermission(Jenkins.ADMINISTER); - if (StringUtils.isBlank(jdbcUrl)) { + Optional optionalPipelineMavenPluginDao = findDaoFromExtension(daoClass); + if(optionalPipelineMavenPluginDao.isEmpty()) { return FormValidation.ok("OK"); } - String driverClass = null; - try { - if (StringUtils.isBlank(jdbcUrl)) { - driverClass = "org.h2.Driver"; - } else if (jdbcUrl.startsWith("jdbc:h2")) { - driverClass = "org.h2.Driver"; - } else if (jdbcUrl.startsWith("jdbc:mysql")) { - driverClass = "com.mysql.cj.jdbc.Driver"; - } else if (jdbcUrl.startsWith("jdbc:postgresql:")) { - driverClass = "org.postgresql.Driver"; - } else { - return FormValidation.error("Unsupported database specified in JDBC url '" + jdbcUrl + "'"); - } - try { - Class.forName(driverClass); - } catch (ClassNotFoundException e) { - if ("com.mysql.cj.jdbc.Driver".equals(driverClass)) { - return FormValidation.error(e, "MySQL JDBC driver '" + driverClass + "' not found, please install the Jenkins 'MySQL API Plugin'" + jdbcUrl); - } else if ("org.postgresql.Driver".equals(driverClass)) { - return FormValidation.error(e, "PostgreSQL JDBC driver '" + driverClass + "' not found, please install the Jenkins 'PostgreSQL API Plugin'" + jdbcUrl); - } else { - throw e; - } - } - - String jdbcUserName, jdbcPassword; - if (StringUtils.isEmpty(jdbcCredentialsId)) { - if (StringUtils.isBlank(jdbcUrl)) { - // embedded database, assume OK - return FormValidation.ok("OK"); - } else { - return FormValidation.error("No credentials specified for JDBC url '" + jdbcUrl + "'"); - } - } else { - UsernamePasswordCredentials jdbcCredentials = (UsernamePasswordCredentials) CredentialsMatchers.firstOrNull( - CredentialsProvider.lookupCredentials(UsernamePasswordCredentials.class, Jenkins.get(), - ACL.SYSTEM, Collections.EMPTY_LIST), - CredentialsMatchers.withId(jdbcCredentialsId)); - if (jdbcCredentials == null) { - return FormValidation.error("Credentials '" + jdbcCredentialsId + "' defined for JDBC URL '" + jdbcUrl + "' not found"); - } - jdbcUserName = jdbcCredentials.getUsername(); - jdbcPassword = Secret.toString(jdbcCredentials.getPassword()); - } - - HikariConfig dsConfig = createHikariConfig(properties, jdbcUrl, jdbcUserName, jdbcPassword); - - try (HikariDataSource ds = new HikariDataSource(dsConfig)) { - try (Connection cnn = ds.getConnection()) { - DatabaseMetaData metaData = cnn.getMetaData(); - // getDatabaseProductVersion(): - // * MySQL: "8.0.13" - // * Amazon Aurora: "5.6.10" - // * MariaDB: "5.5.5-10.2.20-MariaDB", "5.5.5-10.3.11-MariaDB-1:10.3.11+maria~bionic" - String databaseVersionDescription = metaData.getDatabaseProductName() + " " + metaData.getDatabaseProductVersion(); - String databaseRequirement = "MySQL Server version 5.7+ or Amazon Aurora MySQL 5.6+ or MariaDB 10.2+ or PostgreSQL 10+ is required"; - if ("MySQL".equals(metaData.getDatabaseProductName())) { - @Nullable - String amazonAuroraVersion; - try (Statement stmt = cnn.createStatement()) { - try (ResultSet rst = stmt.executeQuery("select AURORA_VERSION()")) { - rst.next(); - amazonAuroraVersion = rst.getString(1); - databaseVersionDescription += " / Aurora " + rst.getString(1); - } catch (SQLException e) { - if (e.getErrorCode() == 1305) { // com.mysql.cj.exceptions.MysqlErrorNumbers.ER_SP_DOES_NOT_EXIST - amazonAuroraVersion = null; - } else { - LOGGER.log(Level.WARNING,"Exception checking Amazon Aurora version", e); - amazonAuroraVersion = null; - } - } - } - @Nullable - String mariaDbVersion = PipelineMavenPluginMySqlDao.extractMariaDbVersion(metaData.getDatabaseProductVersion()); - - switch (metaData.getDatabaseMajorVersion()) { - case 8: - // OK - break; - case 5: - switch (metaData.getDatabaseMinorVersion()) { - case 7: - // ok - break; - case 6: - if (amazonAuroraVersion == null) { - // see JENKINS-54784 - return FormValidation.warning("Non validated MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); - } else { - // we have successfully tested on Amazon Aurora MySQL 5.6.10a - break; - } - case 5: - if (mariaDbVersion == null) { - return FormValidation.warning("Non validated MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); - } else { - // JENKINS-55378 have successfully tested with "5.5.5-10.2.20-MariaDB" - return FormValidation.ok("MariaDB version " + mariaDbVersion + " detected. Please ensure that your MariaDB version is at least version 10.2+"); - } - default: - return FormValidation.error("Non supported MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); - } - break; - default: - return FormValidation.error("Non supported MySQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); - } - } else if ("PostgreSQL".equals(metaData.getDatabaseProductName())) { - @Nullable - String amazonAuroraVersion; // https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Updates.html - try (Statement stmt = cnn.createStatement()) { - try (ResultSet rst = stmt.executeQuery("select AURORA_VERSION()")) { - rst.next(); - amazonAuroraVersion = rst.getString(1); - databaseVersionDescription += " / Aurora " + rst.getString(1); - } catch (SQLException e) { - if ("42883".equals(e.getSQLState())) { // org.postgresql.util.PSQLState.UNDEFINED_FUNCTION.getState() - amazonAuroraVersion = null; - } else { - LOGGER.log(Level.WARNING,"Exception checking Amazon Aurora version", e); - amazonAuroraVersion = null; - } - } - } - switch (metaData.getDatabaseMajorVersion()) { - case 14: - case 13: - case 12: - case 11: - case 10: - case 9: - case 8: - // OK - break; - default: - return FormValidation.warning("Non tested PostgreSQL version " + metaData.getDatabaseProductVersion() + ". " + databaseRequirement); - } - } else { - return FormValidation.warning("Non production grade database. For production workloads, " + databaseRequirement); - } - try (Statement stmt = cnn.createStatement()) { - try (ResultSet rst = stmt.executeQuery("select 1")) { - rst.next(); - // TODO more tests - } - } - return FormValidation.ok(databaseVersionDescription + " is a supported database"); - } catch (SQLException e ){ - return FormValidation.error(e, "Failure to connect to the database " + jdbcUrl); - } - } - } catch (RuntimeException e) { - return FormValidation.error(e, "Failed to test JDBC connection '" + jdbcUrl + "'"); - } catch (ClassNotFoundException e) { - return FormValidation.error(e, "Failed to load JDBC driver '" + driverClass + "' for JDBC connection '" + jdbcUrl + "'"); - } - - } - - private static HikariConfig createHikariConfig(String properties, String jdbcUrl, String jdbcUserName, String jdbcPassword) { - Properties p = new Properties(); - // todo refactor the DAO to inject config defaults in the DAO - if (jdbcUrl.startsWith("jdbc:mysql")) { - // https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby - // https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration - p.setProperty("dataSource.cachePrepStmts", "true"); - p.setProperty("dataSource.prepStmtCacheSize", "250"); - p.setProperty("dataSource.prepStmtCacheSqlLimit", "2048"); - p.setProperty("dataSource.useServerPrepStmts", "true"); - p.setProperty("dataSource.useLocalSessionState", "true"); - p.setProperty("dataSource.rewriteBatchedStatements", "true"); - p.setProperty("dataSource.cacheResultSetMetadata", "true"); - p.setProperty("dataSource.cacheServerConfiguration", "true"); - p.setProperty("dataSource.elideSetAutoCommits", "true"); - p.setProperty("dataSource.maintainTimeStats", "false"); - } else if (jdbcUrl.startsWith("jdbc:postgresql")) { - // no tuning recommendations found for postgresql - } else if (jdbcUrl.startsWith("jdbc:h2")) { - // dsConfig.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); don't specify the datasource due to a classloading issue - } else { - // unsupported config + if (StringUtils.isBlank(jdbcUrl)) { + jdbcUrl = optionalPipelineMavenPluginDao.get().getDefaultJdbcUrl(); } - if (StringUtils.isNotBlank(properties)) { - try { - p.load(new StringReader(properties)); - } catch (IOException e) { - throw new IllegalStateException("Failed to read properties.", e); - } + try { + PipelineMavenPluginDao.Builder.Config config = new PipelineMavenPluginDao.Builder.Config() + .credentialsId(jdbcCredentialsId) + .jdbcUrl(jdbcUrl) + .properties(properties); + return optionalPipelineMavenPluginDao.get().getBuilder().validateConfiguration(config); + } catch (Exception e) { + return FormValidation.error(e, e.getMessage()); } - LOGGER.log(Level.INFO, "Applied pool properties {0}", p); - HikariConfig dsConfig = new HikariConfig(p); - dsConfig.setJdbcUrl(jdbcUrl); - dsConfig.setUsername(jdbcUserName); - dsConfig.setPassword(jdbcPassword); - // to mimic the old behaviour pre JENKINS-69375 fix - dsConfig.setDataSourceProperties(p); - return dsConfig; } @Terminator diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NeededPipelineMavenDatabasePluginAdminMonitor.java b/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NeededPipelineMavenDatabasePluginAdminMonitor.java new file mode 100644 index 00000000..92486c68 --- /dev/null +++ b/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NeededPipelineMavenDatabasePluginAdminMonitor.java @@ -0,0 +1,58 @@ +/* + * The MIT License + * + * Copyright (c) 2016, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.jenkinsci.plugins.pipeline.maven; + +import hudson.Extension; +import hudson.model.AdministrativeMonitor; +import jenkins.model.Jenkins; +import org.apache.commons.lang.StringUtils; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.interceptor.RequirePOST; + +import java.io.IOException; +import java.util.Objects; + +/** + * + */ +@Extension +public class NeededPipelineMavenDatabasePluginAdminMonitor extends AdministrativeMonitor { + + @Override + public boolean isActivated() { + String jdbcUrl = Objects.requireNonNull(GlobalPipelineMavenConfig.get()).getJdbcUrl(); + return (StringUtils.startsWith(jdbcUrl, "jdbc:h2") + || StringUtils.startsWith(jdbcUrl, "jdbc:mysql") + || StringUtils.startsWith(jdbcUrl, "jdbc:postgresql")) + && Jenkins.get().getPlugin("pipeline-maven-database") == null; + } + + @Override + public String getDisplayName() { + return "Pipeline Maven Integration - Need Pipeline Maven Database"; + } + +} \ No newline at end of file diff --git a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitor.java b/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitor.java deleted file mode 100644 index 31cdb2ad..00000000 --- a/jenkins-plugin/src/main/java/org/jenkinsci/plugins/pipeline/maven/NonProductionGradeDatabaseWarningAdministrativeMonitor.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.jenkinsci.plugins.pipeline.maven; - -import hudson.Extension; -import hudson.model.AdministrativeMonitor; - -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.kohsuke.stapler.interceptor.RequirePOST; - -import java.io.IOException; - -/** - * @author Cyrille Le Clerc - */ -@Extension -public class NonProductionGradeDatabaseWarningAdministrativeMonitor extends AdministrativeMonitor { - - @Override - public boolean isActivated() { - String jdbcUrl = GlobalPipelineMavenConfig.get().getJdbcUrl(); - if (jdbcUrl != null && !jdbcUrl.trim().isEmpty()) { - return jdbcUrl.startsWith("jdbc:h2:"); - } - - if (GlobalPipelineMavenConfig.get().isDaoInitialized()) { - return !GlobalPipelineMavenConfig.get().getDao().isEnoughProductionGradeForTheWorkload(); - } - - return false; - } - - @Override - public String getDisplayName() { - return "Pipeline Maven Integration - Non Production Database"; - } - - /** - * Depending on whether the user said "yes" or "no", send him to the right place. - */ - @RequirePOST - public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException { - if (req.hasParameter("no")) { - disable(true); - rsp.sendRedirect(req.getContextPath() + "/manage"); - } else { - rsp.sendRedirect(req.getContextPath() + "/configureTools"); - } - } -} \ No newline at end of file diff --git a/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig/config.jelly b/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig/config.jelly index b48d440f..30ef5be0 100644 --- a/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig/config.jelly +++ b/jenkins-plugin/src/main/resources/org/jenkinsci/plugins/pipeline/maven/GlobalPipelineMavenConfig/config.jelly @@ -27,8 +27,17 @@ THE SOFTWARE. xmlns:f="/lib/form" xmlns:c="/lib/credentials"> + + + -