diff options
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 |