diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-12-13 12:20:34 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-12-14 12:11:53 +0100 |
commit | 610a9a839737166711a29cbb1fdb7911474c5b40 (patch) | |
tree | f9cb60518fd3c4aaf5d8a1d6233a55c0ace06000 /server | |
parent | e2cff9277df4ccaae9098a13d36c52ef70b259fc (diff) | |
download | sonarqube-610a9a839737166711a29cbb1fdb7911474c5b40.tar.gz sonarqube-610a9a839737166711a29cbb1fdb7911474c5b40.zip |
SONAR-8445 move SQ 5.6 create schema migrations out of Ruby
and start some cleaning of migration related code in Ruby
Diffstat (limited to 'server')
26 files changed, 1446 insertions, 339 deletions
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/DbVersionModule.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/DbVersionModule.java index 4fdb281ddbb..0de137980aa 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/DbVersionModule.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/DbVersionModule.java @@ -20,6 +20,7 @@ package org.sonar.server.platform.db.migration.version; import org.sonar.core.platform.Module; +import org.sonar.server.platform.db.migration.version.v56.DbVersion56; import org.sonar.server.platform.db.migration.version.v561.DbVersion561; import org.sonar.server.platform.db.migration.version.v60.DbVersion60; import org.sonar.server.platform.db.migration.version.v61.DbVersion61; @@ -30,6 +31,7 @@ public class DbVersionModule extends Module { @Override protected void configureModule() { add( + DbVersion56.class, DbVersion561.class, DbVersion60.class, DbVersion61.class, diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchema.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchema.java new file mode 100644 index 00000000000..d037512bbf0 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchema.java @@ -0,0 +1,924 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v56; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.version.BigIntegerColumnDef; +import org.sonar.db.version.BooleanColumnDef; +import org.sonar.db.version.ColumnDef; +import org.sonar.db.version.CreateIndexBuilder; +import org.sonar.db.version.CreateTableBuilder; +import org.sonar.db.version.IntegerColumnDef; +import org.sonar.db.version.TinyIntColumnDef; +import org.sonar.db.version.VarcharColumnDef; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import static org.sonar.db.version.BigIntegerColumnDef.newBigIntegerColumnDefBuilder; +import static org.sonar.db.version.BlobColumnDef.newBlobColumnDefBuilder; +import static org.sonar.db.version.BooleanColumnDef.newBooleanColumnDefBuilder; +import static org.sonar.db.version.ClobColumnDef.newClobColumnDefBuilder; +import static org.sonar.db.version.CreateTableBuilder.ColumnFlag.AUTO_INCREMENT; +import static org.sonar.db.version.DecimalColumnDef.newDecimalColumnDefBuilder; +import static org.sonar.db.version.IntegerColumnDef.newIntegerColumnDefBuilder; +import static org.sonar.db.version.TimestampColumnDef.newTimestampColumnDefBuilder; + +public class CreateInitialSchema extends DdlChange { + + public CreateInitialSchema(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + createActiveDashboards(context); + createActiveRuleParameters(context); + createActiveRules(context); + createActivities(context); + createAuthors(context); + createCeActivity(context); + createCeQueue(context); + createDashboards(context); + createDuplicationsIndex(context); + createEvents(context); + createFileSources(context); + createGroupRoles(context); + createGroups(context); + createGroupsUsers(context); + createIssueChanges(context); + createIssueFilterFavourites(context); + createIssueFilters(context); + createIssues(context); + createLoadedTemplates(context); + createManualMeasures(context); + createMeasureFilterFavourites(context); + createMeasureFilters(context); + createMetrics(context); + createNotifications(context); + createPermissionTemplates(context); + createPermTemplatesGroups(context); + createPermTemplatesUsers(context); + createProjectLinks(context); + createProjectMeasures(context); + createProjectQprofiles(context); + createProjects(context); + createProperties(context); + createQualityGateConditions(context); + createQualityGates(context); + createResourceIndex(context); + createRules(context); + createRulesParameters(context); + createRulesProfiles(context); + createSnapshots(context); + createUserRoles(context); + createUserTokens(context); + createUsers(context); + createWidgetProperties(context); + createWidgets(context); + } + + private void createUserTokens(Context context) throws SQLException { + VarcharColumnDef loginCol = newLenientVarcharBuilder("login").setLimit(255).setIsNullable(false).build(); + VarcharColumnDef nameCol = newLenientVarcharBuilder("name").setLimit(100).setIsNullable(false).build(); + VarcharColumnDef tokenHashCol = newLenientVarcharBuilder("token_hash").setLimit(255).setIsNullable(false).build(); + context.execute( + newTableBuilder("user_tokens") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(loginCol) + .addColumn(nameCol) + .addColumn(tokenHashCol) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(false).build()) + .build()); + addIndex(context, "user_tokens", "user_tokens_login_name", true, loginCol, nameCol); + addIndex(context, "user_tokens", "user_tokens_token_hash", true, tokenHashCol); + } + + private void createCeActivity(Context context) throws SQLException { + VarcharColumnDef uuidCol = newLenientVarcharBuilder("uuid").setLimit(40).setIsNullable(false).build(); + VarcharColumnDef isLastKeyCol = newLenientVarcharBuilder("is_last_key").setLimit(55).setIsNullable(false).build(); + BooleanColumnDef isLastCol = newBooleanColumnDefBuilder().setColumnName("is_last").setIsNullable(false).build(); + VarcharColumnDef statusCol = newLenientVarcharBuilder("status").setLimit(15).setIsNullable(false).build(); + VarcharColumnDef componentUuidCol = newLenientVarcharBuilder("component_uuid").setLimit(40).build(); + context.execute( + newTableBuilder("ce_activity") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(uuidCol) + .addColumn(newLenientVarcharBuilder("task_type").setLimit(15).setIsNullable(false).build()) + .addColumn(componentUuidCol) + .addColumn(statusCol) + .addColumn(isLastCol) + .addColumn(isLastKeyCol) + .addColumn(newLenientVarcharBuilder("submitter_login").setLimit(255).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("submitted_at").setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("started_at").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("executed_at").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("updated_at").setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("execution_time_ms").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("snapshot_id").build()) + .build()); + addIndex(context, "ce_activity", "ce_activity_component_uuid", false, componentUuidCol); + addIndex(context, "ce_activity", "ce_activity_islast_status", false, isLastCol, statusCol); + addIndex(context, "ce_activity", "ce_activity_islastkey", false, isLastKeyCol); + addIndex(context, "ce_activity", "ce_activity_uuid", true, uuidCol); + } + + private void createCeQueue(Context context) throws SQLException { + VarcharColumnDef uuidCol = newLenientVarcharBuilder("uuid").setLimit(40).setIsNullable(false).build(); + VarcharColumnDef componentUuidCol = newLenientVarcharBuilder("component_uuid").setLimit(40).build(); + context.execute( + newTableBuilder("ce_queue") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(uuidCol) + .addColumn(newLenientVarcharBuilder("task_type").setLimit(15).setIsNullable(false).build()) + .addColumn(componentUuidCol) + .addColumn(newLenientVarcharBuilder("status").setLimit(15).build()) + .addColumn(newLenientVarcharBuilder("submitter_login").setLimit(255).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("started_at").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("updated_at").setIsNullable(false).build()) + .build()); + addIndex(context, "ce_queue", "ce_queue_component_uuid", false, componentUuidCol); + addIndex(context, "ce_queue", "ce_queue_uuid", true, uuidCol); + } + + private void createFileSources(Context context) throws SQLException { + VarcharColumnDef projectUuidCol = newLenientVarcharBuilder("project_uuid").setLimit(50).setIsNullable(false).build(); + BigIntegerColumnDef updatedAtCol = newBigIntegerColumnDefBuilder().setColumnName("updated_at").setIsNullable(false).build(); + VarcharColumnDef dataTypeCol = newLenientVarcharBuilder("data_type").setLimit(20).build(); + VarcharColumnDef fileUuidCol = newLenientVarcharBuilder("file_uuid").setLimit(50).setIsNullable(false).build(); + context.execute( + newTableBuilder("file_sources") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(projectUuidCol) + .addColumn(fileUuidCol) + .addColumn(newClobColumnDefBuilder().setColumnName("line_hashes").build()) + .addColumn(newLenientVarcharBuilder("data_hash").setLimit(50).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(false).build()) + .addColumn(updatedAtCol) + .addColumn(newLenientVarcharBuilder("src_hash").setLimit(50).build()) + .addColumn(newBlobColumnDefBuilder().setColumnName("binary_data").build()) + .addColumn(dataTypeCol) + .addColumn(newLenientVarcharBuilder("revision").setLimit(100).build()) + .build()); + addIndex(context, "file_sources", "file_sources_project_uuid", false, projectUuidCol); + addIndex(context, "file_sources", "file_sources_updated_at", false, updatedAtCol); + addIndex(context, "file_sources", "file_sources_uuid_type", true, fileUuidCol, dataTypeCol); + } + + private void createActivities(Context context) throws SQLException { + VarcharColumnDef keeCol = newLenientVarcharBuilder("log_key").setLimit(255).build(); + context.execute( + newTableBuilder("activities") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newLenientVarcharBuilder("user_login").setLimit(255).build()) + .addColumn(newClobColumnDefBuilder().setColumnName("data_field").build()) + .addColumn(newLenientVarcharBuilder("log_type").setLimit(50).build()) + .addColumn(newLenientVarcharBuilder("log_action").setLimit(50).build()) + .addColumn(newLenientVarcharBuilder("log_message").setLimit(4000).build()) + .addColumn(keeCol) + .build()); + + addIndex(context, "activities", "activities_log_key", true, keeCol); + } + + private void createPermTemplatesGroups(Context context) throws SQLException { + context.execute( + newTableBuilder("perm_templates_groups") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("group_id").build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("template_id").setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("permission_reference").setLimit(64).setIsNullable(false).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").build()) + .build()); + } + + private void createPermTemplatesUsers(Context context) throws SQLException { + context.execute( + newTableBuilder("perm_templates_users") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("user_id").setIsNullable(false).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("template_id").setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("permission_reference").setLimit(64).setIsNullable(false).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").build()) + .build()); + } + + private void createPermissionTemplates(Context context) throws SQLException { + context.execute( + newTableBuilder("permission_templates") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("name").setLimit(100).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("kee").setLimit(100).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(4000).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").build()) + .addColumn(newLenientVarcharBuilder("key_pattern").setLimit(500).build()) + .build()); + } + + private void createIssueFilterFavourites(Context context) throws SQLException { + VarcharColumnDef loginCol = newLenientVarcharBuilder("user_login").setLimit(255).setIsNullable(false).build(); + context.execute( + newTableBuilder("issue_filter_favourites") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(loginCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("issue_filter_id").setIsNullable(false).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .build()); + addIndex(context, "issue_filter_favourites", "issue_filter_favs_user", false, loginCol); + } + + private void createIssueFilters(Context context) throws SQLException { + VarcharColumnDef nameCol = newLenientVarcharBuilder("name").setLimit(100).setIsNullable(false).build(); + context.execute( + newTableBuilder("issue_filters") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(nameCol) + .addColumn(newLenientVarcharBuilder("user_login").setLimit(255).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("shared").setIsNullable(false).setDefaultValue(false).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(4000).build()) + .addColumn(newClobColumnDefBuilder().setColumnName("data").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").build()) + .build()); + addIndex(context, "issue_filters", "issue_filters_name", false, nameCol); + } + + private void createIssueChanges(Context context) throws SQLException { + VarcharColumnDef issueKeyCol = newLenientVarcharBuilder("issue_key").setLimit(50).setIsNullable(false).build(); + VarcharColumnDef keeCol = newLenientVarcharBuilder("kee").setLimit(50).build(); + context.execute( + newTableBuilder("issue_changes") + .addPkColumn(newBigIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(keeCol) + .addColumn(issueKeyCol) + .addColumn(newLenientVarcharBuilder("user_login").setLimit(255).build()) + .addColumn(newLenientVarcharBuilder("change_type").setLimit(20).build()) + .addColumn(newClobColumnDefBuilder().setColumnName("change_data").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("updated_at").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("issue_change_creation_date").build()) + .build()); + addIndex(context, "issue_changes", "issue_changes_issue_key", false, issueKeyCol); + addIndex(context, "issue_changes", "issue_changes_kee", false, keeCol); + } + + private void createIssues(Context context) throws SQLException { + VarcharColumnDef assigneeCol = newLenientVarcharBuilder("assignee").setLimit(255).build(); + VarcharColumnDef componentUuidCol = newLenientVarcharBuilder("component_uuid").setLimit(50).build(); + BigIntegerColumnDef issueCreationDateCol = newBigIntegerColumnDefBuilder().setColumnName("issue_creation_date").build(); + VarcharColumnDef keeCol = newLenientVarcharBuilder("kee").setLimit(50).setIsNullable(false).build(); + VarcharColumnDef projectUuidCol = newLenientVarcharBuilder("project_uuid").setLimit(50).build(); + VarcharColumnDef resolutionCol = newLenientVarcharBuilder("resolution").setLimit(20).build(); + IntegerColumnDef ruleIdCol = newIntegerColumnDefBuilder().setColumnName("rule_id").build(); + BigIntegerColumnDef updatedAtCol = newBigIntegerColumnDefBuilder().setColumnName("updated_at").build(); + context.execute( + newTableBuilder("issues") + .addPkColumn(newBigIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(keeCol) + .addColumn(ruleIdCol) + .addColumn(newLenientVarcharBuilder("severity").setLimit(10).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("manual_severity").setIsNullable(false).build()) + // unit has been fixed in SonarQube 5.6 (see migration 1151, SONAR-7493) + .addColumn(newLenientVarcharBuilder("message").setIgnoreOracleUnit(false).setLimit(4000).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("line").build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("gap").setPrecision(30).setScale(20).build()) + .addColumn(newLenientVarcharBuilder("status").setLimit(20).build()) + .addColumn(resolutionCol) + .addColumn(newLenientVarcharBuilder("checksum").setLimit(1000).build()) + .addColumn(newLenientVarcharBuilder("reporter").setLimit(255).build()) + .addColumn(assigneeCol) + .addColumn(newLenientVarcharBuilder("author_login").setLimit(255).build()) + .addColumn(newLenientVarcharBuilder("action_plan_key").setLimit(50).build()) + .addColumn(newLenientVarcharBuilder("issue_attributes").setLimit(4000).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("effort").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(updatedAtCol) + .addColumn(issueCreationDateCol) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("issue_update_date").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("issue_close_date").build()) + .addColumn(newLenientVarcharBuilder("tags").setLimit(4000).build()) + .addColumn(componentUuidCol) + .addColumn(projectUuidCol) + .addColumn(newBlobColumnDefBuilder().setColumnName("locations").build()) + .addColumn(new TinyIntColumnDef.Builder().setColumnName("issue_type").build()) + .build()); + addIndex(context, "issues", "issues_assignee", false, assigneeCol); + addIndex(context, "issues", "issues_component_uuid", false, componentUuidCol); + addIndex(context, "issues", "issues_creation_date", false, issueCreationDateCol); + addIndex(context, "issues", "issues_kee", true, keeCol); + addIndex(context, "issues", "issues_project_uuid", false, projectUuidCol); + addIndex(context, "issues", "issues_resolution", false, resolutionCol); + addIndex(context, "issues", "issues_rule_id", false, ruleIdCol); + addIndex(context, "issues", "issues_updated_at", false, updatedAtCol); + } + + private void createMeasureFilterFavourites(Context context) throws SQLException { + IntegerColumnDef userIdCol = newIntegerColumnDefBuilder().setColumnName("user_id").setIsNullable(false).build(); + context.execute( + newTableBuilder("measure_filter_favourites") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(userIdCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("measure_filter_id").setIsNullable(false).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .build()); + addIndex(context, "measure_filter_favourites", "measure_filter_favs_userid", false, userIdCol); + } + + private void createMeasureFilters(Context context) throws SQLException { + VarcharColumnDef nameCol = newLenientVarcharBuilder("name").setLimit(100).setIsNullable(false).build(); + context.execute( + newTableBuilder("measure_filters") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(nameCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("user_id").build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("shared").setDefaultValue(false).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(4000).build()) + .addColumn(newClobColumnDefBuilder().setColumnName("data").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").build()) + .build()); + addIndex(context, "measure_filters", "measure_filters_name", false, nameCol); + } + + private void createAuthors(Context context) throws SQLException { + VarcharColumnDef loginCol = newLenientVarcharBuilder("login").setLimit(255).build(); + context.execute( + newTableBuilder("authors") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("person_id").setIsNullable(false).build()) + .addColumn(loginCol) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").build()) + .build()); + addIndex(context, "authors", "uniq_author_logins", true, loginCol); + } + + private void createResourceIndex(Context context) throws SQLException { + VarcharColumnDef keeCol = newLenientVarcharBuilder("kee").setLimit(400).setIsNullable(false).build(); + IntegerColumnDef resourceIdCol = newIntegerColumnDefBuilder().setColumnName("resource_id").setIsNullable(false).build(); + context.execute( + newTableBuilder("resource_index") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(keeCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("position").setIsNullable(false).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("name_size").setIsNullable(false).build()) + .addColumn(resourceIdCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("root_project_id").setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("qualifier").setLimit(10).setIsNullable(false).build()) + .build()); + addIndex(context, "resource_index", "resource_index_key", false, keeCol); + addIndex(context, "resource_index", "resource_index_rid", false, resourceIdCol); + } + + private void createLoadedTemplates(Context context) throws SQLException { + context.execute( + newTableBuilder("loaded_templates") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("kee").setLimit(200).build()) + .addColumn(newLenientVarcharBuilder("template_type").setLimit(15).build()) + .build()); + } + + private void createMetrics(Context context) throws SQLException { + VarcharColumnDef nameCol = newLenientVarcharBuilder("name").setLimit(64).setIsNullable(false).build(); + context.execute( + newTableBuilder("metrics") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(nameCol) + .addColumn(newLenientVarcharBuilder("description").setLimit(255).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("direction").setIsNullable(false).setDefaultValue(0).build()) + .addColumn(newLenientVarcharBuilder("domain").setLimit(64).build()) + .addColumn(newLenientVarcharBuilder("short_name").setLimit(64).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("qualitative").setDefaultValue(false).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("val_type").setLimit(8).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("user_managed").setDefaultValue(false).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("enabled").setDefaultValue(true).build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("worst_value").setPrecision(38).setScale(20).build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("best_value").setPrecision(38).setScale(20).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("optimized_best_value").build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("hidden").build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("delete_historical_data").build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("decimal_scale").build()) + .build()); + addIndex(context, "metrics", "metrics_unique_name", true, nameCol); + } + + private void createDashboards(Context context) throws SQLException { + context.execute( + newTableBuilder("dashboards") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("user_id").build()) + .addColumn(newLenientVarcharBuilder("name").setLimit(256).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(1000).build()) + .addColumn(newLenientVarcharBuilder("column_layout").setLimit(20).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("shared").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("is_global").build()) + .build()); + } + + private void createUsers(Context context) throws SQLException { + VarcharColumnDef loginCol = newLenientVarcharBuilder("login").setLimit(255).build(); + BigIntegerColumnDef updatedAtCol = newBigIntegerColumnDefBuilder().setColumnName("updated_at").build(); + context.execute( + newTableBuilder("users") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(loginCol) + .addColumn(newLenientVarcharBuilder("name").setLimit(200).build()) + .addColumn(newLenientVarcharBuilder("email").setLimit(100).build()) + .addColumn(newLenientVarcharBuilder("crypted_password").setLimit(40).build()) + .addColumn(newLenientVarcharBuilder("salt").setLimit(40).build()) + .addColumn(newLenientVarcharBuilder("remember_token").setLimit(500).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("remember_token_expires_at").build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("active").setDefaultValue(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(updatedAtCol) + .addColumn(newLenientVarcharBuilder("scm_accounts").setLimit(4000).build()) + .addColumn(newLenientVarcharBuilder("external_identity").setLimit(255).build()) + .addColumn(newLenientVarcharBuilder("external_identity_provider").setLimit(100).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("user_local").build()) + .build()); + addIndex(context, "users", "users_login", true, loginCol); + addIndex(context, "users", "users_updated_at", false, updatedAtCol); + } + + private void createActiveRuleParameters(Context context) throws SQLException { + context.execute( + newTableBuilder("active_rule_parameters") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("active_rule_id").setIsNullable(false).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("rules_parameter_id").setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("value").setLimit(4000).build()) + .addColumn(newLenientVarcharBuilder("rules_parameter_key").setLimit(128).build()) + .build()); + } + + private void createActiveRules(Context context) throws SQLException { + IntegerColumnDef profileIdCol = newIntegerColumnDefBuilder().setColumnName("profile_id").setIsNullable(false).build(); + IntegerColumnDef ruleIdCol = newIntegerColumnDefBuilder().setColumnName("rule_id").setIsNullable(false).build(); + context.execute( + newTableBuilder("active_rules") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(profileIdCol) + .addColumn(ruleIdCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("failure_level").setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("inheritance").setLimit(10).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("updated_at").build()) + .build()); + addIndex(context, "active_rules", "uniq_profile_rule_ids", true, profileIdCol, ruleIdCol); + } + + private void createUserRoles(Context context) throws SQLException { + IntegerColumnDef userIdCol = newIntegerColumnDefBuilder().setColumnName("user_id").build(); + IntegerColumnDef resourceIdCol = newIntegerColumnDefBuilder().setColumnName("resource_id").build(); + context.execute( + newTableBuilder("user_roles") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(userIdCol) + .addColumn(resourceIdCol) + .addColumn(newLenientVarcharBuilder("role").setLimit(64).setIsNullable(false).build()) + .build()); + addIndex(context, "user_roles", "user_roles_resource", false, resourceIdCol); + addIndex(context, "user_roles", "user_roles_user", false, userIdCol); + } + + private void createActiveDashboards(Context context) throws SQLException { + IntegerColumnDef dashboardIdCol = newIntegerColumnDefBuilder().setColumnName("dashboard_id").setIsNullable(false).build(); + IntegerColumnDef userIdCol = newIntegerColumnDefBuilder().setColumnName("user_id").build(); + context.execute( + newTableBuilder("active_dashboards") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(dashboardIdCol) + .addColumn(userIdCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("order_index").build()) + .build()); + addIndex(context, "active_dashboards", "active_dashboards_dashboardid", false, dashboardIdCol); + addIndex(context, "active_dashboards", "active_dashboards_userid", false, userIdCol); + } + + private void createNotifications(Context context) throws SQLException { + context.execute( + newTableBuilder("notifications") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newBlobColumnDefBuilder().setColumnName("data").build()) + .build()); + } + + private void createSnapshots(Context context) throws SQLException { + IntegerColumnDef projectIdCol = newIntegerColumnDefBuilder().setColumnName("project_id").setIsNullable(false).build(); + IntegerColumnDef rootProjectIdCol = newIntegerColumnDefBuilder().setColumnName("root_project_id").setIsNullable(true).build(); + IntegerColumnDef parentSnapshotIdCol = newIntegerColumnDefBuilder().setColumnName("parent_snapshot_id").setIsNullable(true).build(); + VarcharColumnDef qualifierCol = newLenientVarcharBuilder("qualifier").setLimit(10).setIsNullable(true).build(); + IntegerColumnDef rootSnapshotIdCol = newIntegerColumnDefBuilder().setColumnName("root_snapshot_id").setIsNullable(true).build(); + context.execute( + newTableBuilder("snapshots") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(projectIdCol) + .addColumn(parentSnapshotIdCol) + .addColumn(newLenientVarcharBuilder("status").setLimit(4).setIsNullable(false).setDefaultValue("U").build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("islast").setIsNullable(false).setDefaultValue(false).build()) + .addColumn(newLenientVarcharBuilder("scope").setLimit(3).setIsNullable(true).build()) + .addColumn(qualifierCol) + .addColumn(rootSnapshotIdCol) + .addColumn(newLenientVarcharBuilder("version").setLimit(500).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("path").setLimit(500).setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("depth").setIsNullable(true).build()) + .addColumn(rootProjectIdCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("purge_status").setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period1_mode").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period1_param").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period2_mode").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period2_param").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period3_mode").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period3_param").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period4_mode").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period4_param").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period5_mode").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("period5_param").setLimit(100).setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("build_date").setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("period1_date").setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("period2_date").setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("period3_date").setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("period4_date").setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("period5_date").setIsNullable(true).build()) + .build()); + addIndex(context, "snapshots", "snapshot_project_id", false, projectIdCol); + addIndex(context, "snapshots", "snapshots_parent", false, parentSnapshotIdCol); + addIndex(context, "snapshots", "snapshots_qualifier", false, qualifierCol); + addIndex(context, "snapshots", "snapshots_root", false, rootSnapshotIdCol); + addIndex(context, "snapshots", "snapshots_root_project_id", false, rootProjectIdCol); + } + + private void createGroups(Context context) throws SQLException { + context.execute( + newTableBuilder("groups") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("name").setLimit(500).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(200).setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").setIsNullable(true).build()) + .build()); + } + + private void createWidgets(Context context) throws SQLException { + IntegerColumnDef dashboardId = newIntegerColumnDefBuilder().setColumnName("dashboard_id").setIsNullable(false).build(); + VarcharColumnDef widgetKey = newLenientVarcharBuilder("widget_key").setLimit(256).setIsNullable(false).build(); + context.execute( + newTableBuilder("widgets") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(dashboardId) + .addColumn(widgetKey) + .addColumn(newLenientVarcharBuilder("name").setLimit(256).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(1000).setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("column_index").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("row_index").setIsNullable(true).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("configured").setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("resource_id").setIsNullable(true).build()) + .build()); + addIndex(context, "widgets", "widgets_dashboards", false, dashboardId); + addIndex(context, "widgets", "widgets_widgetkey", false, widgetKey); + } + + private void createProjectQprofiles(Context context) throws SQLException { + VarcharColumnDef projectUuid = newLenientVarcharBuilder("project_uuid").setLimit(50).setIsNullable(false).build(); + VarcharColumnDef profileKey = newLenientVarcharBuilder("profile_key").setLimit(50).setIsNullable(false).build(); + context.execute( + newTableBuilder("project_qprofiles") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(projectUuid) + .addColumn(profileKey) + .build()); + addIndex(context, "project_qprofiles", "uniq_project_qprofiles", true, projectUuid, profileKey); + } + + private void createRulesProfiles(Context context) throws SQLException { + VarcharColumnDef keeCol = newLenientVarcharBuilder("kee").setLimit(255).setIsNullable(false).build(); + context.execute( + newTableBuilder("rules_profiles") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("name").setLimit(100).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("language").setLimit(20).setIsNullable(true).build()) + .addColumn(keeCol) + .addColumn(newLenientVarcharBuilder("parent_kee").setLimit(255).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("rules_updated_at").setLimit(100).setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").setIsNullable(true).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("is_default").setIsNullable(false).build()) + .build()); + addIndex(context, "rules_profiles", "uniq_qprof_key", true, keeCol); + } + + private void createRulesParameters(Context context) throws SQLException { + IntegerColumnDef ruleIdCol = newIntegerColumnDefBuilder().setColumnName("rule_id").setIsNullable(false).build(); + context.execute( + newTableBuilder("rules_parameters") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(ruleIdCol) + .addColumn(newLenientVarcharBuilder("name").setLimit(128).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(4000).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("param_type").setLimit(512).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("default_value").setLimit(4000).setIsNullable(true).build()) + .build()); + addIndex(context, "rules_parameters", "rules_parameters_rule_id", false, ruleIdCol); + } + + private void createGroupsUsers(Context context) throws SQLException { + BigIntegerColumnDef userIdCol = newBigIntegerColumnDefBuilder().setColumnName("user_id").setIsNullable(true).build(); + BigIntegerColumnDef groupIdCol = newBigIntegerColumnDefBuilder().setColumnName("group_id").setIsNullable(true).build(); + context.execute( + newTableBuilder("groups_users") + .addColumn(userIdCol) + .addColumn(groupIdCol) + .build()); + addIndex(context, "groups_users", "index_groups_users_on_user_id", false, userIdCol); + addIndex(context, "groups_users", "index_groups_users_on_group_id", false, groupIdCol); + addIndex(context, "groups_users", "groups_users_unique", true, groupIdCol, userIdCol); + } + + private void createProjectMeasures(Context context) throws SQLException { + IntegerColumnDef personIdCol = newIntegerColumnDefBuilder().setColumnName("person_id").build(); + IntegerColumnDef metricIdCol = newIntegerColumnDefBuilder().setColumnName("metric_id").setIsNullable(false).build(); + IntegerColumnDef snapshotIdCol = newIntegerColumnDefBuilder().setColumnName("snapshot_id").setIsNullable(true).build(); + context.execute( + newTableBuilder("project_measures") + .addPkColumn(newBigIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newDecimalColumnDefBuilder().setColumnName("value").setPrecision(38).setScale(20).build()) + .addColumn(metricIdCol) + .addColumn(snapshotIdCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("rule_id").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("rules_category_id").setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("text_value").setLimit(4000).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("tendency").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("measure_date").build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("project_id").build()) + .addColumn(newLenientVarcharBuilder("alert_status").setLimit(5).build()) + .addColumn(newLenientVarcharBuilder("alert_text").setLimit(4000).build()) + .addColumn(newLenientVarcharBuilder("url").setLimit(2000).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(4000).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("rule_priority").build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("characteristic_id").build()) + .addColumn(personIdCol) + .addColumn(newDecimalColumnDefBuilder().setColumnName("variation_value_1").setPrecision(38).setScale(20).build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("variation_value_2").setPrecision(38).setScale(20).build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("variation_value_3").setPrecision(38).setScale(20).build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("variation_value_4").setPrecision(38).setScale(20).build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("variation_value_5").setPrecision(38).setScale(20).build()) + .addColumn(newBlobColumnDefBuilder().setColumnName("measure_data").build()) + .build()); + addIndex(context, "project_measures", "measures_sid_metric", false, snapshotIdCol, metricIdCol); + addIndex(context, "project_measures", "measures_person", false, personIdCol); + } + + private void createManualMeasures(Context context) throws SQLException { + VarcharColumnDef componentUuidCol = newLenientVarcharBuilder("component_uuid").setLimit(50).build(); + context.execute( + newTableBuilder("manual_measures") + .addPkColumn(newBigIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("metric_id").setIsNullable(false).build()) + .addColumn(newDecimalColumnDefBuilder().setColumnName("value").setPrecision(38).setScale(20).build()) + .addColumn(newLenientVarcharBuilder("text_value").setLimit(4000).build()) + .addColumn(newLenientVarcharBuilder("user_login").setLimit(255).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(4000).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("updated_at").build()) + .addColumn(componentUuidCol) + .build()); + addIndex(context, "manual_measures", "manual_measures_component_uuid", false, componentUuidCol); + } + + private void createProjects(Context context) throws SQLException { + VarcharColumnDef keeCol = newLenientVarcharBuilder("kee").setLimit(400).build(); + VarcharColumnDef moduleUuidCol = newLenientVarcharBuilder("module_uuid").setLimit(50).build(); + VarcharColumnDef projectUuidCol = newLenientVarcharBuilder("project_uuid").setLimit(50).build(); + VarcharColumnDef qualifierCol = newLenientVarcharBuilder("qualifier").setLimit(10).build(); + IntegerColumnDef rootIdCol = newIntegerColumnDefBuilder().setColumnName("root_id").build(); + VarcharColumnDef uuidCol = newLenientVarcharBuilder("uuid").setLimit(50).build(); + context.execute( + newTableBuilder("projects") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("name").setLimit(2000).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(2000).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("enabled").setDefaultValue(true).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("scope").setLimit(3).build()) + .addColumn(qualifierCol) + .addColumn(keeCol) + .addColumn(rootIdCol) + .addColumn(newLenientVarcharBuilder("language").setLimit(20).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("copy_resource_id").build()) + .addColumn(newLenientVarcharBuilder("long_name").setLimit(2000).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("person_id").build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").build()) + .addColumn(newLenientVarcharBuilder("path").setLimit(2000).build()) + .addColumn(newLenientVarcharBuilder("deprecated_kee").setLimit(400).build()) + .addColumn(uuidCol) + .addColumn(projectUuidCol) + .addColumn(moduleUuidCol) + .addColumn(newLenientVarcharBuilder("module_uuid_path").setLimit(4000).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("authorization_updated_at").build()) + .build()); + addIndex(context, "projects", "projects_kee", true, keeCol); + addIndex(context, "projects", "projects_module_uuid", false, moduleUuidCol); + addIndex(context, "projects", "projects_project_uuid", false, projectUuidCol); + addIndex(context, "projects", "projects_qualifier", false, qualifierCol); + addIndex(context, "projects", "projects_root_id", false, rootIdCol); + addIndex(context, "projects", "projects_uuid", true, uuidCol); + } + + private void createGroupRoles(Context context) throws SQLException { + IntegerColumnDef groupIdCol = newIntegerColumnDefBuilder().setColumnName("group_id").setIsNullable(true).build(); + IntegerColumnDef resourceIdCol = newIntegerColumnDefBuilder().setColumnName("resource_id").setIsNullable(true).build(); + VarcharColumnDef roleCol = newLenientVarcharBuilder("role").setLimit(64).setIsNullable(false).build(); + context.execute( + newTableBuilder("group_roles") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(groupIdCol) + .addColumn(resourceIdCol) + .addColumn(roleCol) + .build()); + addIndex(context, "group_roles", "group_roles_resource", false, resourceIdCol); + addIndex(context, "group_roles", "uniq_group_roles", true, groupIdCol, resourceIdCol, roleCol); + } + + private void createRules(Context context) throws SQLException { + VarcharColumnDef pluginRuleKeyCol = newLenientVarcharBuilder("plugin_rule_key").setLimit(200).setIsNullable(false).build(); + VarcharColumnDef pluginNameCol = newLenientVarcharBuilder("plugin_name").setLimit(255).setIsNullable(false).build(); + context.execute( + newTableBuilder("rules") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("name").setLimit(200).setIsNullable(true).build()) + .addColumn(pluginRuleKeyCol) + .addColumn(newLenientVarcharBuilder("plugin_config_key").setLimit(200).setIsNullable(true).build()) + .addColumn(pluginNameCol) + .addColumn(newClobColumnDefBuilder().setColumnName("description").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("priority").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("template_id").setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("status").setLimit(40).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("language").setLimit(20).setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("note_created_at").setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("note_updated_at").setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("note_user_login").setLimit(255).setIsNullable(true).build()) + .addColumn(newClobColumnDefBuilder().setColumnName("note_data").setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("remediation_function").setLimit(200).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("def_remediation_function").setLimit(20).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("remediation_gap_mult").setLimit(20).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("def_remediation_gap_mult").setLimit(20).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("remediation_base_effort").setLimit(20).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("def_remediation_base_effort").setLimit(20).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("gap_description").setLimit(4000).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("tags").setLimit(4000).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("system_tags").setLimit(4000).setIsNullable(true).build()) + .addColumn(newBooleanColumnDefBuilder().setColumnName("is_template").setIsNullable(false).setDefaultValue(false).build()) + .addColumn(newLenientVarcharBuilder("description_format").setLimit(20).setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(true).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("updated_at").setIsNullable(true).build()) + .addColumn(new TinyIntColumnDef.Builder().setColumnName("rule_type").setIsNullable(true).build()) + .build()); + addIndex(context, "rules", "rules_repo_key", true, pluginRuleKeyCol, pluginNameCol); + } + + private void createWidgetProperties(Context context) throws SQLException { + IntegerColumnDef widgetIdCol = newIntegerColumnDefBuilder().setColumnName("widget_id").setIsNullable(false).build(); + context.execute( + newTableBuilder("widget_properties") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(widgetIdCol) + .addColumn(newLenientVarcharBuilder("kee").setLimit(100).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("text_value").setLimit(4000).setIsNullable(true).build()) + .build()); + addIndex(context, "widget_properties", "widget_properties_widgets", false, widgetIdCol); + } + + private void createEvents(Context context) throws SQLException { + VarcharColumnDef componentUuid = newLenientVarcharBuilder("component_uuid").setLimit(50).setIsNullable(true).build(); + IntegerColumnDef snapshotId = newIntegerColumnDefBuilder().setColumnName("snapshot_id").setIsNullable(true).build(); + context.execute( + newTableBuilder("events") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("name").setLimit(400).setIsNullable(true).build()) + .addColumn(snapshotId) + .addColumn(newLenientVarcharBuilder("category").setLimit(50).build()) + .addColumn(newLenientVarcharBuilder("description").setLimit(4000).build()) + .addColumn(newLenientVarcharBuilder("event_data").setLimit(4000).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("event_date").setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").setIsNullable(false).build()) + .addColumn(componentUuid) + .build()); + addIndex(context, "events", "events_component_uuid", false, componentUuid); + addIndex(context, "events", "events_snapshot_id", false, snapshotId); + } + + private void createQualityGates(Context context) throws SQLException { + VarcharColumnDef nameCol = newLenientVarcharBuilder("name").setLimit(100).setIsNullable(false).build(); + context.execute( + newTableBuilder("quality_gates") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(nameCol) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").setIsNullable(true).build()) + .build()); + addIndex(context, "quality_gates", "uniq_quality_gates", true, nameCol); + } + + private void createQualityGateConditions(Context context) throws SQLException { + context.execute( + newTableBuilder("quality_gate_conditions") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("qgate_id").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("metric_id").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("period").setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("operator").setLimit(3).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("value_error").setLimit(64).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("value_warning").setLimit(64).setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("created_at").setIsNullable(true).build()) + .addColumn(newTimestampColumnDefBuilder().setColumnName("updated_at").setIsNullable(true).build()) + .build()); + } + + private void createProperties(Context context) throws SQLException { + VarcharColumnDef propKey = newLenientVarcharBuilder("prop_key").setLimit(512).setIsNullable(true).build(); + context.execute( + newTableBuilder("properties") + // do not define as primary key on purpose -> already set in org.sonar.db.version.v61.CreateTableProperties2 + .addColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build()) + .addColumn(propKey) + .addColumn(newIntegerColumnDefBuilder().setColumnName("resource_id").setIsNullable(true).build()) + .addColumn(newClobColumnDefBuilder().setColumnName("text_value").setIsNullable(true).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("user_id").setIsNullable(true).build()) + .build()); + addIndex(context, "properties", "properties_key", false, propKey); + } + + private void createProjectLinks(Context context) throws SQLException { + context.execute( + newTableBuilder("project_links") + .addPkColumn(newIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newLenientVarcharBuilder("link_type").setLimit(20).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("name").setLimit(128).setIsNullable(true).build()) + .addColumn(newLenientVarcharBuilder("href").setLimit(2048).setIsNullable(false).build()) + .addColumn(newLenientVarcharBuilder("component_uuid").setLimit(2048).setIsNullable(true).build()) + .build()); + } + + private void createDuplicationsIndex(Context context) throws SQLException { + VarcharColumnDef hashCol = newLenientVarcharBuilder("hash").setLimit(50).setIsNullable(false).build(); + IntegerColumnDef snapshotIdCol = newIntegerColumnDefBuilder().setColumnName("snapshot_id").setIsNullable(false).build(); + context.execute( + newTableBuilder("duplications_index") + .addPkColumn(newBigIntegerColumnDefBuilder().setColumnName("id").setIsNullable(false).build(), AUTO_INCREMENT) + .addColumn(newIntegerColumnDefBuilder().setColumnName("project_snapshot_id").setIsNullable(false).build()) + .addColumn(snapshotIdCol) + .addColumn(hashCol) + .addColumn(newIntegerColumnDefBuilder().setColumnName("index_in_file").setIsNullable(false).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("start_line").setIsNullable(false).build()) + .addColumn(newIntegerColumnDefBuilder().setColumnName("end_line").setIsNullable(false).build()) + .build()); + addIndex(context, "duplications_index", "duplications_index_hash", false, hashCol); + addIndex(context, "duplications_index", "duplications_index_sid", false, snapshotIdCol); + } + + private void addIndex(Context context, String table, String index, boolean unique, ColumnDef... columns) throws SQLException { + CreateIndexBuilder builder = new CreateIndexBuilder(getDialect()) + .setTable(table) + .setName(index) + .setUnique(unique); + for (ColumnDef column : columns) { + builder.addColumn(column); + } + context.execute(builder.build()); + } + + private static VarcharColumnDef.Builder newLenientVarcharBuilder(String column) { + return new VarcharColumnDef.Builder().setColumnName(column).setIgnoreOracleUnit(true); + } + + private CreateTableBuilder newTableBuilder(String tableName) { + return new CreateTableBuilder(getDialect(), tableName); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/DbVersion56.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/DbVersion56.java new file mode 100644 index 00000000000..c8295486b0d --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/DbVersion56.java @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v56; + +import org.sonar.server.platform.db.migration.step.MigrationStepRegistry; +import org.sonar.server.platform.db.migration.version.DbVersion; + +public class DbVersion56 implements DbVersion { + @Override + public void addSteps(MigrationStepRegistry registry) { + registry + .add(1, "Create initial schema", CreateInitialSchema.class) + .add(2, "Populate initial schema", PopulateInitialSchema.class); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchema.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchema.java new file mode 100644 index 00000000000..ef48be58073 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchema.java @@ -0,0 +1,121 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v56; + +import java.sql.SQLException; +import java.util.Date; +import org.sonar.api.utils.System2; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.step.DataChange; + +public class PopulateInitialSchema extends DataChange { + + private static final String ADMINS_GROUP = "sonar-administrators"; + private static final String USERS_GROUP = "sonar-users"; + private static final String ADMIN_USER = "admin"; + + private final System2 system2; + + public PopulateInitialSchema(Database db, System2 system2) { + super(db); + this.system2 = system2; + } + + @Override + public void execute(Context context) throws SQLException { + insertGroups(context); + insertGroupRoles(context); + insertAdminUser(context); + insertGroupMemberships(context); + + } + + private void insertGroups(Context context) throws SQLException { + truncateTable(context, "groups"); + + Date now = new Date(system2.now()); + context.prepareUpsert("insert into groups (name, description, created_at, updated_at) values (?, ?, ?, ?)") + .setString(1, ADMINS_GROUP) + .setString(2, "System administrators") + .setDate(3, now) + .setDate(4, now) + .addBatch() + .setString(1, USERS_GROUP) + .setString(2, "Any new users created will automatically join this group") + .setDate(3, now) + .setDate(4, now) + .addBatch() + .execute() + .commit(); + } + + private static void insertGroupRoles(Context context) throws SQLException { + truncateTable(context, "group_roles"); + + // admin group + context.prepareUpsert("insert into group_roles (group_id, resource_id, role) values ((select id from groups where name='" + ADMINS_GROUP + "'), null, ?)") + .setString(1, "admin").addBatch() + .setString(1, "profileadmin").addBatch() + .setString(1, "gateadmin").addBatch() + .setString(1, "shareDashboard").addBatch() + .setString(1, "provisioning").addBatch() + .execute() + .commit(); + + // anyone + context.prepareUpsert("insert into group_roles (group_id, resource_id, role) values (null, null, ?)") + .setString(1, "scan").addBatch() + .setString(1, "provisioning").addBatch() + .execute() + .commit(); + } + + private void insertAdminUser(Context context) throws SQLException { + truncateTable(context, "users"); + + long now = system2.now(); + context.prepareUpsert("insert into users " + + "(login, name, email, external_identity, external_identity_provider, user_local, crypted_password, salt, " + + "created_at, updated_at, remember_token, remember_token_expires_at) " + + "values ('" + ADMIN_USER + "', 'Administrator', '', 'admin', 'sonarqube', ?, " + + "'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', ?, ?, null, null)") + .setBoolean(1, true) + .setLong(2, now) + .setLong(3, now) + .execute() + .commit(); + } + + private static void insertGroupMemberships(Context context) throws SQLException { + truncateTable(context, "groups_users"); + + context.prepareUpsert("insert into groups_users (user_id, group_id) values " + + "((select id from users where login='" + ADMIN_USER + "'), (select id from groups where name=?))") + .setString(1, ADMINS_GROUP).addBatch() + .setString(1, USERS_GROUP).addBatch() + .execute() + .commit(); + } + + private static void truncateTable(Context context, String table) throws SQLException { + context.prepareUpsert("truncate table " + table).execute().commit(); + } + +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/package-info.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/package-info.java new file mode 100644 index 00000000000..832de3c3198 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v56/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.platform.db.migration.version.v56; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/DbVersionModuleTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/DbVersionModuleTest.java index 6f9226ab604..8a2b5a42cc9 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/DbVersionModuleTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/DbVersionModuleTest.java @@ -36,7 +36,7 @@ public class DbVersionModuleTest { underTest.configure(container); assertThat(container.getPicoContainer().getComponentAdapters()) - .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5); + .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 6); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchemaTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchemaTest.java new file mode 100644 index 00000000000..61a39f3dae5 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchemaTest.java @@ -0,0 +1,100 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v56; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CreateInitialSchemaTest { + + @Rule + public final DbTester dbTester = DbTester.createForSchema(System2.INSTANCE, CreateInitialSchemaTest.class, "empty.sql"); + + private CreateInitialSchema underTest = new CreateInitialSchema(dbTester.database()); + + @Test + public void creates_tables_on_empty_db() throws Exception { + underTest.execute(); + + List<String> tables = new ArrayList<>(); + try (Connection connection = dbTester.openConnection(); + ResultSet rs = connection.getMetaData().getTables(null, null, null, new String[] {"TABLE"})) { + + while (rs.next()) { + tables.add(rs.getString("TABLE_NAME").toLowerCase(Locale.ENGLISH)); + } + } + assertThat(tables).containsOnly( + "active_dashboards", + "active_rules", + "active_rule_parameters", + "activities", + "authors", + "ce_activity", + "ce_queue", + "dashboards", + "duplications_index", + "events", + "file_sources", + "groups", + "groups_users", + "group_roles", + "issues", + "issue_changes", + "issue_filters", + "issue_filter_favourites", + "loaded_templates", + "manual_measures", + "measure_filters", + "measure_filter_favourites", + "metrics", + "notifications", + "permission_templates", + "perm_templates_groups", + "perm_templates_users", + "projects", + "project_links", + "project_measures", + "project_qprofiles", + "properties", + "quality_gates", + "quality_gate_conditions", + "resource_index", + "rules", + "rules_parameters", + "rules_profiles", + "snapshots", + "users", + "user_roles", + "user_tokens", + "widgets", + "widget_properties"); + } + +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/DbVersion56Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/DbVersion56Test.java new file mode 100644 index 00000000000..d62347556e6 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/DbVersion56Test.java @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v56; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationCount; +import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber; + +public class DbVersion56Test { + private DbVersion56 underTest = new DbVersion56(); + + @Test + public void verify_no_support_component() { + assertThat(underTest.getSupportComponents()).isEmpty(); + } + + @Test + public void migrationNumber_starts_at_1153() { + verifyMinimumMigrationNumber(underTest, 1); + } + + @Test + public void verify_migration_count() { + verifyMigrationCount(underTest, 2); + } + + +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchemaTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchemaTest.java new file mode 100644 index 00000000000..5d167c53e49 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchemaTest.java @@ -0,0 +1,131 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.version.v56; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.core.util.stream.Collectors; +import org.sonar.db.DbTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class PopulateInitialSchemaTest { + + private static final long NOW = 1_500L; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private System2 system2 = mock(System2.class); + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, PopulateInitialSchemaTest.class, "v56.sql"); + + private PopulateInitialSchema underTest = new PopulateInitialSchema(db.database(), system2); + + @Test + public void migration_inserts_users_and_groups() throws SQLException { + when(system2.now()).thenReturn(NOW); + + underTest.execute(); + + verifyGroup("sonar-administrators", "System administrators"); + verifyGroup("sonar-users", "Any new users created will automatically join this group"); + verifyRolesOfAdminsGroup(); + verifyRolesOfUsersGroup(); + verifyRolesOfAnyone(); + verifyAdminUser(); + verifyMembershipOfAdminUser(); + } + + private void verifyRolesOfAdminsGroup() { + List<String> roles = selectRoles("sonar-administrators"); + assertThat(roles).containsOnly("admin", "profileadmin", "gateadmin", "shareDashboard", "provisioning"); + } + + private void verifyRolesOfUsersGroup() { + assertThat(selectRoles("sonar-users")).isEmpty(); + } + + private void verifyRolesOfAnyone() { + List<Map<String, Object>> rows = db.select("select gr.role as \"role\" " + + "from group_roles gr where gr.group_id is null"); + List<String> roles = rows.stream() + .map(row -> (String) row.get("role")) + .collect(Collectors.toArrayList()); + assertThat(roles).containsOnly("provisioning", "scan"); + } + + private List<String> selectRoles(String groupName) { + List<Map<String, Object>> rows = db.select("select gr.role as \"role\" " + + "from group_roles gr " + + "inner join groups g on gr.group_id = g.id " + + "where g.name='" + groupName + "'"); + return rows.stream() + .map(row -> (String) row.get("role")) + .collect(Collectors.toArrayList()); + } + + private void verifyGroup(String expectedName, String expectedDescription) { + Map<String, Object> cols = db.selectFirst("select name as \"name\", description as \"description\", " + + "created_at as \"created_at\", updated_at as \"updated_at\" " + + "from groups where name='" + expectedName + "'"); + assertThat(cols.get("name")).isEqualTo(expectedName); + assertThat(cols.get("description")).isEqualTo(expectedDescription); + assertThat(cols.get("created_at")).isNotNull(); + } + + private void verifyMembershipOfAdminUser() { + List<Map<String, Object>> rows = db.select("select g.name as \"groupName\" from groups g " + + "inner join groups_users gu on gu.group_id = g.id " + + "inner join users u on gu.user_id = u.id " + + "where u.login='admin'"); + List<String> groupNames = rows.stream() + .map(row -> (String) row.get("groupName")) + .collect(Collectors.toArrayList()); + assertThat(groupNames).containsOnly("sonar-administrators", "sonar-users"); + } + + private void verifyAdminUser() { + Map<String, Object> cols = db.selectFirst("select login as \"login\", name as \"name\", email as \"email\", " + + "external_identity as \"external_identity\", external_identity_provider as \"external_identity_provider\", " + + "user_local as \"user_local\", crypted_password as \"crypted_password\", salt as \"salt\", created_at as \"created_at\", " + + "updated_at as \"updated_at\", remember_token as \"remember_token\", remember_token_expires_at as \"remember_token_expires_at\" " + + "from users where login='admin'"); + assertThat(cols.get("login")).isEqualTo("admin"); + assertThat(cols.get("name")).isEqualTo("Administrator"); + assertThat(cols.get("email")).isEqualTo(""); + assertThat(cols.get("user_local")).isEqualTo(true); + assertThat(cols.get("crypted_password")).isEqualTo("a373a0e667abb2604c1fd571eb4ad47fe8cc0878"); + assertThat(cols.get("salt")).isEqualTo("48bc4b0d93179b5103fd3885ea9119498e9d161b"); + assertThat(cols.get("created_at")).isEqualTo(NOW); + assertThat(cols.get("updated_at")).isEqualTo(NOW); + assertThat(cols.get("remember_token")).isNull(); + assertThat(cols.get("remember_token_expires_at")).isNull(); + } + +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchemaTest/empty.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchemaTest/empty.sql new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v56/CreateInitialSchemaTest/empty.sql diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchemaTest/v56.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchemaTest/v56.sql new file mode 100644 index 00000000000..d0c61c969ac --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v56/PopulateInitialSchemaTest/v56.sql @@ -0,0 +1,47 @@ +CREATE TABLE "GROUPS_USERS" ( + "USER_ID" INTEGER, + "GROUP_ID" INTEGER +); +CREATE INDEX "INDEX_GROUPS_USERS_ON_GROUP_ID" ON "GROUPS_USERS" ("GROUP_ID"); +CREATE INDEX "INDEX_GROUPS_USERS_ON_USER_ID" ON "GROUPS_USERS" ("USER_ID"); +CREATE UNIQUE INDEX "GROUPS_USERS_UNIQUE" ON "GROUPS_USERS" ("GROUP_ID", "USER_ID"); + + +CREATE TABLE "GROUPS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "NAME" VARCHAR(500), + "DESCRIPTION" VARCHAR(200), + "CREATED_AT" TIMESTAMP, + "UPDATED_AT" TIMESTAMP +); + + +CREATE TABLE "GROUP_ROLES" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "GROUP_ID" INTEGER, + "RESOURCE_ID" INTEGER, + "ROLE" VARCHAR(64) NOT NULL +); +CREATE UNIQUE INDEX "UNIQ_GROUP_ROLES" ON "GROUP_ROLES" ("GROUP_ID", "RESOURCE_ID", "ROLE"); +CREATE INDEX "GROUP_ROLES_RESOURCE" ON "GROUP_ROLES" ("RESOURCE_ID"); + + +CREATE TABLE "USERS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "LOGIN" VARCHAR(255), + "NAME" VARCHAR(200), + "EMAIL" VARCHAR(100), + "CRYPTED_PASSWORD" VARCHAR(40), + "SALT" VARCHAR(40), + "REMEMBER_TOKEN" VARCHAR(500), + "REMEMBER_TOKEN_EXPIRES_AT" TIMESTAMP, + "ACTIVE" BOOLEAN DEFAULT TRUE, + "SCM_ACCOUNTS" VARCHAR(4000), + "EXTERNAL_IDENTITY" VARCHAR(255), + "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100), + "USER_LOCAL" BOOLEAN, + "CREATED_AT" BIGINT, + "UPDATED_AT" BIGINT +); +CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN"); +CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT"); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java index 1435468e39a..1746941c190 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java @@ -29,7 +29,6 @@ import org.sonar.api.server.ServerSide; import org.sonar.api.utils.log.Loggers; import org.sonar.db.DbClient; import org.sonar.db.DdlUtils; -import org.sonar.db.version.MigrationStep; import org.sonar.server.plugins.ServerPluginRepository; /** @@ -42,16 +41,13 @@ import org.sonar.server.plugins.ServerPluginRepository; public class DatabaseMigrator implements Startable { private final DbClient dbClient; - private final MigrationStep[] migrations; private final ServerUpgradeStatus serverUpgradeStatus; /** * ServerPluginRepository is used to ensure H2 schema creation is done only after copy of bundle plugins have been done */ - public DatabaseMigrator(DbClient dbClient, MigrationStep[] migrations, ServerUpgradeStatus serverUpgradeStatus, - ServerPluginRepository unused) { + public DatabaseMigrator(DbClient dbClient, ServerUpgradeStatus serverUpgradeStatus, ServerPluginRepository unused) { this.dbClient = dbClient; - this.migrations = migrations; this.serverUpgradeStatus = serverUpgradeStatus; } @@ -89,28 +85,6 @@ public class DatabaseMigrator implements Startable { return false; } - public void executeMigration(String className) { - MigrationStep migration = getMigration(className); - try { - migration.execute(); - - } catch (Exception e) { - // duplication between log and exception because webapp does not correctly log initial stacktrace - String msg = "Fail to execute database migration: " + className; - Loggers.get(getClass()).error(msg, e); - throw new IllegalStateException(msg, e); - } - } - - private MigrationStep getMigration(String className) { - for (MigrationStep migration : migrations) { - if (migration.getClass().getName().equals(className)) { - return migration; - } - } - throw new IllegalArgumentException("Database migration not found: " + className); - } - @VisibleForTesting protected void createSchema(Connection connection, String dialectId) { DdlUtils.createSchema(connection, dialectId, false); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java index 9e9f2e95479..65b92653ff3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java @@ -25,7 +25,6 @@ import org.sonar.core.i18n.RuleI18nManager; import org.sonar.core.platform.PluginClassloaderFactory; import org.sonar.core.platform.PluginLoader; import org.sonar.db.charset.DatabaseCharsetChecker; -import org.sonar.db.version.MigrationStepModule; import org.sonar.server.platform.DefaultServerUpgradeStatus; import org.sonar.server.platform.StartupMetadataProvider; import org.sonar.server.platform.db.CheckDatabaseCharsetAtStartup; @@ -75,9 +74,7 @@ public class PlatformLevel2 extends PlatformLevel { add(DatabaseMigrationStateImpl.class, DatabaseMigrationExecutorServiceImpl.class); // Ruby DB Migration - add( - DatabaseMigrator.class, - MigrationStepModule.class); + add(DatabaseMigrator.class); addIfStartupLeader( DatabaseCharsetChecker.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java index aa5f0f6f694..9aa211f5fbc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java @@ -55,13 +55,12 @@ import org.sonar.server.authentication.IdentityProviderRepository; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.platform.PersistentSettings; import org.sonar.server.platform.Platform; -import org.sonar.server.platform.db.migrations.DatabaseMigrator; import org.sonar.server.platform.db.migration.DatabaseMigrationState; import org.sonar.server.platform.ws.UpgradesAction; import org.sonar.server.user.NewUserNotifier; import static com.google.common.collect.Lists.newArrayList; -import static org.sonar.server.platform.db.migration.DatabaseMigrationState.*; +import static org.sonar.server.platform.db.migration.DatabaseMigrationState.Status; public final class JRubyFacade { @@ -153,9 +152,8 @@ public final class JRubyFacade { return get(Database.class); } - // Only used by Java migration - public DatabaseMigrator databaseMigrator() { - return get(DatabaseMigrator.class); + public boolean isDbUptodate() { + return getContainer().getComponentByType(DatabaseVersion.class).getStatus() == DatabaseVersion.Status.UP_TO_DATE; } /* PROFILES CONSOLE : RULES AND METRIC THRESHOLDS */ diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/db/migrations/DatabaseMigratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/db/migrations/DatabaseMigratorTest.java index 6fca4c37125..a3bac3ac496 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/db/migrations/DatabaseMigratorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/db/migrations/DatabaseMigratorTest.java @@ -31,7 +31,6 @@ import org.sonar.db.DbSession; import org.sonar.db.dialect.Dialect; import org.sonar.db.dialect.H2; import org.sonar.db.dialect.MySql; -import org.sonar.db.version.MigrationStep; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.anyBoolean; @@ -45,14 +44,13 @@ public class DatabaseMigratorTest { @Rule public ExpectedException thrown = ExpectedException.none(); - DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS); - MigrationStep[] migrations = new MigrationStep[] {new FakeMigrationStep()}; - ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class); - DatabaseMigrator migrator; + private DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS); + private ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class); + private DatabaseMigrator migrator; @Before public void setUp() { - migrator = new DatabaseMigrator(dbClient, migrations, serverUpgradeStatus, null); + migrator = new DatabaseMigrator(dbClient, serverUpgradeStatus, null); } @Test @@ -64,21 +62,6 @@ public class DatabaseMigratorTest { } @Test - public void fail_if_execute_unknown_migration() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Database migration not found: org.xxx.UnknownMigration"); - - migrator.executeMigration("org.xxx.UnknownMigration"); - } - - @Test - public void execute_migration() { - assertThat(FakeMigrationStep.executed).isFalse(); - migrator.executeMigration(FakeMigrationStep.class.getName()); - assertThat(FakeMigrationStep.executed).isTrue(); - } - - @Test public void should_create_schema_on_h2() { Dialect supportedDialect = new H2(); when(dbClient.getDatabase().getDialect()).thenReturn(supportedDialect); @@ -88,7 +71,7 @@ public class DatabaseMigratorTest { when(dbClient.openSession(false)).thenReturn(session); when(serverUpgradeStatus.isFreshInstall()).thenReturn(true); - DatabaseMigrator databaseMigrator = new DatabaseMigrator(dbClient, migrations, serverUpgradeStatus, null) { + DatabaseMigrator databaseMigrator = new DatabaseMigrator(dbClient, serverUpgradeStatus, null) { @Override protected void createSchema(Connection connection, String dialectId) { } @@ -97,12 +80,4 @@ public class DatabaseMigratorTest { assertThat(databaseMigrator.createDatabase()).isTrue(); } - public static class FakeMigrationStep implements MigrationStep { - static boolean executed = false; - - @Override - public void execute() { - executed = true; - } - } } diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddAnalysisUuidColumnToDuplicationsIndex.java b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddAnalysisUuidColumnToDuplicationsIndex.java index 04f86a0ed14..557449e68c2 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddAnalysisUuidColumnToDuplicationsIndex.java +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddAnalysisUuidColumnToDuplicationsIndex.java @@ -22,7 +22,6 @@ package org.sonar.db.version.v60; import java.sql.SQLException; import org.sonar.db.Database; import org.sonar.db.version.AddColumnsBuilder; -import org.sonar.db.version.DdlChange; import static org.sonar.db.version.VarcharColumnDef.UUID_VARCHAR_SIZE; import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; @@ -42,4 +41,4 @@ public class AddAnalysisUuidColumnToDuplicationsIndex extends DdlChange { .build()); } -}
\ No newline at end of file +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddComponentUuidColumnToDuplicationsIndex.java b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddComponentUuidColumnToDuplicationsIndex.java index a25cf2cc376..8612d57b378 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddComponentUuidColumnToDuplicationsIndex.java +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/AddComponentUuidColumnToDuplicationsIndex.java @@ -22,7 +22,6 @@ package org.sonar.db.version.v60; import java.sql.SQLException; import org.sonar.db.Database; import org.sonar.db.version.AddColumnsBuilder; -import org.sonar.db.version.DdlChange; import static org.sonar.db.version.VarcharColumnDef.UUID_VARCHAR_SIZE; import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; @@ -43,4 +42,4 @@ public class AddComponentUuidAndAnalysisUuidColumnToDuplicationsIndex extends Dd .build()); } -}
\ No newline at end of file +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/DeleteOrphanDuplicationsIndexRowsWithoutComponent.java b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/DeleteOrphanDuplicationsIndexRowsWithoutComponent.java index 763dd89a98a..0a05c5194b3 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/DeleteOrphanDuplicationsIndexRowsWithoutComponent.java +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/DeleteOrphanDuplicationsIndexRowsWithoutComponent.java @@ -21,7 +21,6 @@ package org.sonar.db.version.v60; import java.sql.SQLException; import org.sonar.db.Database; -import org.sonar.db.version.BaseDataChange; import org.sonar.db.version.MassUpdate; public class DeleteOrphanDuplicationsIndexRowsWithoutComponent extends BaseDataChange { @@ -42,4 +41,4 @@ public class DeleteOrphanDuplicationsIndexRowsWithoutComponent extends BaseDataC }); } -}
\ No newline at end of file +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/MakeComponentUuidNotNullOnDuplicationsIndex.java b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/MakeComponentUuidNotNullOnDuplicationsIndex.java index 6233d86fb40..8ced13cac4d 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/MakeComponentUuidNotNullOnDuplicationsIndex.java +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v1/MakeComponentUuidNotNullOnDuplicationsIndex.java @@ -22,7 +22,6 @@ package org.sonar.db.version.v60; import java.sql.SQLException; import org.sonar.db.Database; import org.sonar.db.version.AlterColumnsBuilder; -import org.sonar.db.version.DdlChange; import static org.sonar.db.version.VarcharColumnDef.UUID_VARCHAR_SIZE; import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; @@ -42,4 +41,4 @@ public class MakeComponentUuidNotNullOnDuplicationsIndex extends DdlChange { .build()); } -}
\ No newline at end of file +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/AddComponentUuidAndAnalysisUuidColumnToDuplicationsIndex.java b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/AddComponentUuidAndAnalysisUuidColumnToDuplicationsIndex.java index 8e9280fa5ec..8cc16f323a9 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/AddComponentUuidAndAnalysisUuidColumnToDuplicationsIndex.java +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/AddComponentUuidAndAnalysisUuidColumnToDuplicationsIndex.java @@ -22,7 +22,6 @@ package org.sonar.db.version.v60; import java.sql.SQLException; import org.sonar.db.Database; import org.sonar.db.version.AddColumnsBuilder; -import org.sonar.db.version.DdlChange; import static org.sonar.db.version.VarcharColumnDef.UUID_VARCHAR_SIZE; import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; @@ -42,4 +41,4 @@ public class AddComponentUuidColumnToDuplicationsIndex extends DdlChange { .build()); } -}
\ No newline at end of file +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/MakeComponentUuidAndAnalysisUuidNotNullOnDuplicationsIndex.java b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/MakeComponentUuidAndAnalysisUuidNotNullOnDuplicationsIndex.java index e365b126bfd..9e522216532 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/MakeComponentUuidAndAnalysisUuidNotNullOnDuplicationsIndex.java +++ b/server/sonar-server/src/test/resources/org/sonar/server/computation/task/projectanalysis/filemove/FileMoveDetectionStepTest/v2/MakeComponentUuidAndAnalysisUuidNotNullOnDuplicationsIndex.java @@ -22,7 +22,6 @@ package org.sonar.db.version.v60; import java.sql.SQLException; import org.sonar.db.Database; import org.sonar.db.version.AlterColumnsBuilder; -import org.sonar.db.version.DdlChange; import static org.sonar.db.version.VarcharColumnDef.UUID_VARCHAR_SIZE; import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; @@ -43,4 +42,4 @@ public class MakeComponentUuidAndAnalysisUuidNotNullOnDuplicationsIndex extends .build()); } -}
\ No newline at end of file +} diff --git a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb index 3c375e4607b..00f28b34ec3 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb @@ -100,164 +100,9 @@ Rails::Initializer.run do |config| # Prevent appearance of ANSI style escape sequences in logs config.active_record.colorize_logging = false - # Use SQL instead of Active Record's schema dumper when creating the test database. - # This is necessary if your schema can't be completely dumped by the schema dumper, - # like if you have constraints or database-specific column types - # config.active_record.schema_format = :sql - - # Activate observers that should always be running - # Please note that observers generated using script/generate observer need to have an _observer suffix - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer end -class ActiveRecord::Migration - def self.dialect - ActiveRecord::Base.configurations[ENV['RAILS_ENV']]['dialect'] - end - - def self.column_exists?(table_name, column_name) - columns(table_name).any?{ |c| c.name == column_name.to_s } - end - - def self.add_index(table_name, column_name, options = {}) - # ActiveRecord can generate index names longer than 30 characters, but that's - # not supported by Oracle, the "Enterprise" database. - # For this reason we force to set name of indexes. - raise ArgumentError, 'Missing index name' unless options[:name] - - unless index_exists?(table_name, column_name, :name => options[:name]) - super(table_name, column_name, options) - end - end - - def self.remove_column(table_name, column_name) - if column_exists?(table_name, column_name) - super(table_name, column_name) - end - end - - def self.add_column(table_name, column_name, type, options = {}) - unless column_exists?(table_name, column_name) - super(table_name, column_name, type, options) - end - end - - def self.add_varchar_index(table_name, column_name, options = {}) - if dialect()=='mysql' && !options[:length] - # Index of varchar column is limited to 767 bytes on mysql (<= 255 UTF-8 characters) - # See http://jira.sonarsource.com/browse/SONAR-4137 and - # http://dev.mysql.com/doc/refman/5.6/en/innodb-restrictions.html - options[:length]=255 - end - add_index table_name, column_name, options - end - - def self.execute_java_migration(classname) - Java::OrgSonarServerUi::JRubyFacade.getInstance().databaseMigrator().executeMigration(classname) - end - - def self.alter_to_big_primary_key(tablename) - case dialect() - when "postgre" - execute "ALTER TABLE #{tablename} ALTER COLUMN id TYPE bigint" - when "mysql" - execute "ALTER TABLE #{tablename} CHANGE id id BIGINT AUTO_INCREMENT" - when "h2" - # not needed? - when "oracle" - # do nothing, oracle integer are big enough - when "sqlserver" - constraint=select_one "select name from sysobjects where parent_obj = (select id from sysobjects where name = '#{tablename}')" - execute "ALTER TABLE #{tablename} DROP CONSTRAINT #{constraint["name"]}" - execute "ALTER TABLE #{tablename} ALTER COLUMN id bigint" - execute "ALTER TABLE #{tablename} ADD PRIMARY KEY(id)" - end - end - - def self.alter_to_big_integer(tablename, columnname, indexname=nil) - case dialect() - when "sqlserver" - execute "DROP INDEX #{indexname} on #{tablename}" if indexname - change_column(tablename, columnname, :big_integer, :null => true) - execute "CREATE INDEX #{indexname} on #{tablename}(#{columnname})" if indexname - else - change_column(tablename, columnname, :big_integer, :null => true) - end - end - - def self.add_primary_key(tablename, columnname) - if dialect()=="mysql" - execute "ALTER TABLE `#{tablename}` ADD PRIMARY KEY (`#{columnname}`)" - else - execute "ALTER TABLE #{tablename} ADD CONSTRAINT pk_#{tablename} PRIMARY KEY (#{columnname})" - end - end - - # SONAR-4178 - def self.create_table(table_name, options = {}) - # Oracle constraint (see names of triggers and indices) - raise ArgumentError, "Table name is too long: #{table_name}" if table_name.to_s.length>25 - - super(table_name, options) - create_id_trigger(table_name) if dialect()=='oracle' && options[:id] != false - end - - def drop_table(table_name, options = {}) - super(table_name, options) - drop_id_trigger(table_name) if dialect()=='oracle' - end - - def self.rename_table(old_table_name, new_table_name, options = {}) - drop_id_trigger(old_table_name) if dialect()=='oracle' && options[:id] != false - super(old_table_name, new_table_name) - create_id_trigger(new_table_name) if dialect()=='oracle' && options[:id] != false - end - - def self.create_id_trigger(table) - execute_ddl("create trigger for table #{table}", - - %{CREATE OR REPLACE TRIGGER #{table}_idt - BEFORE INSERT ON #{table} - FOR EACH ROW - BEGIN - IF :new.id IS null THEN - SELECT #{table}_seq.nextval INTO :new.id FROM dual; - END IF; - END;}) - end - - def self.drop_id_trigger(table) - drop_trigger("#{table}_idt") - end - - def self.drop_trigger(trigger_name) - execute_ddl("drop trigger #{trigger_name}", "DROP TRIGGER #{trigger_name}") - end - - def self.write(text="") - # See migration.rb, the method write directly calls "puts" - Java::OrgSlf4j::LoggerFactory::getLogger('DbMigration').info(text) if verbose - end - - def self.drop_index_quietly(table, index) - begin - remove_index table, :name => index - rescue - #ignore - end - end - - - private - - def self.execute_ddl(message, ddl) - say_with_time(message) do - ActiveRecord::Base.connection.execute(ddl) - end - end -end - # patch for SONAR-1182. GWT does not support ISO8601 dates that end with 'Z' # http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/i18n/client/DateTimeFormat.html module ActiveSupport diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/001_create_initial_schema.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/001_create_initial_schema.rb deleted file mode 100644 index 049022bd018..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/001_create_initial_schema.rb +++ /dev/null @@ -1,24 +0,0 @@ - # - # SonarQube, open source software quality management tool. - # Copyright (C) 2008-2016 SonarSource - # mailto:contact AT sonarsource DOT com - # - # SonarQube is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public - # License as published by the Free Software Foundation; either - # version 3 of the License, or (at your option) any later version. - # - # SonarQube is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - # Lesser General Public License for more details. - # - # You should have received a copy of the GNU Lesser General Public License - # along with this program; if not, write to the Free Software Foundation, - # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - # -class CreateInitialSchema < ActiveRecord::Migration - def self.up - execute_java_migration('org.sonar.db.version.v56.CreateInitialSchema') - end -end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/002_populate_initial_schema.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/002_populate_initial_schema.rb deleted file mode 100644 index 3687c57fe3d..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/002_populate_initial_schema.rb +++ /dev/null @@ -1,24 +0,0 @@ - # - # SonarQube, open source software quality management tool. - # Copyright (C) 2008-2016 SonarSource - # mailto:contact AT sonarsource DOT com - # - # SonarQube is free software; you can redistribute it and/or - # modify it under the terms of the GNU Lesser General Public - # License as published by the Free Software Foundation; either - # version 3 of the License, or (at your option) any later version. - # - # SonarQube is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - # Lesser General Public License for more details. - # - # You should have received a copy of the GNU Lesser General Public License - # along with this program; if not, write to the Free Software Foundation, - # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - # -class PopulateInitialSchema < ActiveRecord::Migration - def self.up - execute_java_migration('org.sonar.db.version.v56.PopulateInitialSchema') - end -end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/README.txt b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/README.txt deleted file mode 100644 index 3cd43b6e984..00000000000 --- a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/README.txt +++ /dev/null @@ -1,55 +0,0 @@ -HOW TO ADD A MIGRATION - -* Jump some versions when adding the first Ruby on Rails migration of a new sonar version. For example if sonar 2.10 is 193, then sonar 2.11 should start at 200. -* Complete the DDL files for H2 : - + sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl - + sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql : - - add "INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('<THE MIGRATION ID>')" -* Update the migration id defined in org.sonar.db.version.DatabaseVersion -* If a table is added or removed, then edit org.sonar.db.version.DatabaseVersion#TABLES -* Changes in bulk must be handled using Java migrations based on org.sonar.db.version.MassUpdate : - + Create the class for the Java migration in package org.sonar.db.version.vXYZ, where XYZ is the version of SQ without dots - + Add the class to org.sonar.db.version.MigrationStepModule - + Create a Ruby migration which calls execute_java_migration('org.sonar.db.version.vXYZ.MyMigration') - + Simple, "one to one" migrations that only need to be split by 1000 can rely on class org.sonar.db.version.BaseDataChange - - -RECOMMENDATIONS - -* Prefer to add nullable columns to avoid problems during migration, EXCEPT for booleans. For booleans: - - * columns must be NON-nullable but default value (false) must NOT be set in database. It allows to fully define the model programmatically. - * column names must be chosen so that the default value is actually false. - * E.g.: rule_failures.switched_off - -* Always create an index with a name : add_index "action_plans", "project_id", :name => "action_plans_project_id" - Note that this name is limited to 30 characters because of Oracle constraint. - -* Silently ignore failures when adding an index that has already been created by users. It can occur when the index - is not created in the same migration script than the table. - - begin - add_index "action_plans", "project_id", :name => "action_plans_project_id" - rescue - # ignore - end - -* Use faux models when touching rows (SELECT/INSERT/UPDATE/DELETE). See http://guides.rubyonrails.org/migrations.html#using-models-in-your-migrations - for more details. Note that associations must not be used. - IMPORTANT : do not use faux models for user models (User, Group, UserRole, GroupRole) because of required associations and password encryption. - - - class MyMigration < ActiveRecord::Migration - # This is the faux model. It only maps columns. No functional methods. - class Metric < ActiveRecord::Base - end - - def self.up - # it’s a good idea to call reset_column_information to refresh the ActiveRecord cache for the model prior to - # updating data in the database - Metric.reset_column_information - Metric.find(:all) do |m| - m.save - end - end - end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb b/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb index 52f032d0441..9656163835a 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/lib/database_version.rb @@ -53,7 +53,7 @@ class DatabaseVersion def self.uptodate? unless $uptodate - $uptodate = (current_version>=target_version) + $uptodate = Java::OrgSonarServerUi::JRubyFacade.getInstance().isDbUptodate() end $uptodate end @@ -63,7 +63,6 @@ class DatabaseVersion end def self.upgrade_and_start - ActiveRecord::Migrator.migrate(migrations_path) Java::OrgSonarServerPlatform::Platform.getInstance().upgradeDb() Java::OrgSonarServerPlatform::Platform.getInstance().doStart() load_java_web_services |