@@ -28,6 +28,7 @@ public class DbVersion79 implements DbVersion { | |||
registry | |||
.add(2800, "Truncate environment variables and system properties from existing scanner reports", | |||
TruncateEnvAndSystemVarsFromScannerContext.class) | |||
.add(2801, "populate install version and install date internal properties", PopulateInstallDateAndVersion.class); | |||
.add(2801, "populate install version and install date internal properties", PopulateInstallDateAndVersion.class) | |||
.add(2802, "Migrate property 'sonar.pullrequest.provider' value from VSTS to Azure DevOps", MigrateVstsProviderToAzureDevOps.class); | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info 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.v79; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
@SupportsBlueGreen | |||
public class MigrateVstsProviderToAzureDevOps extends DataChange { | |||
private static final String VSTS = "VSTS"; | |||
private static final String VSTS_TFS = "VSTS / TFS"; | |||
public MigrateVstsProviderToAzureDevOps(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("select id, text_value from properties " + | |||
" where prop_key = 'sonar.pullrequest.provider' and text_value in ('" + VSTS + "', '" + VSTS_TFS + "')"); | |||
massUpdate.update("update properties " + | |||
" set text_value= ?, " + | |||
" clob_value = null " + | |||
" where id = ?"); | |||
massUpdate.rowPluralName("PR provider properties"); | |||
massUpdate.execute((row, update) -> { | |||
update.setString(1, convert(row.getString(2))); | |||
update.setLong(2, row.getLong(1)); | |||
return true; | |||
}); | |||
} | |||
private static String convert(String oldValue) { | |||
switch (oldValue) { | |||
case VSTS: | |||
return "Azure DevOps Services"; | |||
case VSTS_TFS: | |||
return "Azure DevOps Services/Server"; | |||
default: | |||
throw new IllegalStateException("Unexpected value: " + oldValue); | |||
} | |||
} | |||
} |
@@ -35,7 +35,7 @@ public class DbVersion79Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 2); | |||
verifyMigrationCount(underTest, 3); | |||
} | |||
} |
@@ -0,0 +1,105 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info 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.v79; | |||
import java.sql.SQLException; | |||
import java.util.HashMap; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.assertj.core.groups.Tuple; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.db.CoreDbTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
public class MigrateVstsProviderToAzureDevOpsTest { | |||
private final static String SELECT_PROPERTIES = "SELECT prop_key, is_empty, text_value, clob_value FROM properties"; | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(MigrateVstsProviderToAzureDevOpsTest.class, "properties.sql"); | |||
private MigrateVstsProviderToAzureDevOps underTest = new MigrateVstsProviderToAzureDevOps(db.database()); | |||
@Test | |||
public void migration_must_update_the_database() throws SQLException { | |||
insertProperty("sonar.pullrequest.provider", "any.value_here", null, false); | |||
insertProperty("sonar.pullrequest.provider", "VSTS", null, false); | |||
insertProperty("sonar.pullrequest.provider", "VSTS / TFS", null, false); | |||
insertProperty("whatever.property", "nothingspecial", null, false); | |||
insertProperty("whatever.property", null, "nothing.special", false); | |||
underTest.execute(); | |||
assertPropertyContainsInAnyOrder( | |||
tuple("sonar.pullrequest.provider", "any.value_here", null, false), | |||
tuple("sonar.pullrequest.provider", "Azure DevOps Services", null, false), | |||
tuple("sonar.pullrequest.provider", "Azure DevOps Services/Server", null, false), // Single change | |||
tuple("whatever.property", "nothingspecial", null, false), | |||
tuple("whatever.property", null, "nothing.special", false) | |||
); | |||
} | |||
@Test | |||
public void migration_must_be_reentrant() throws SQLException { | |||
insertProperty("sonar.pullrequest.provider", "any.value_here", null, false); | |||
insertProperty("sonar.pullrequest.provider", "VSTS", null, false); | |||
insertProperty("sonar.pullrequest.provider", "VSTS / TFS", null, false); | |||
insertProperty("whatever.property", "nothingspecial", null, false); | |||
insertProperty("whatever.property", null, "nothing.special", false); | |||
underTest.execute(); | |||
underTest.execute(); | |||
assertPropertyContainsInAnyOrder( | |||
tuple("sonar.pullrequest.provider", "any.value_here", null, false), | |||
tuple("sonar.pullrequest.provider", "Azure DevOps Services", null, false), | |||
tuple("sonar.pullrequest.provider", "Azure DevOps Services/Server", null, false), // Single change | |||
tuple("whatever.property", "nothingspecial", null, false), | |||
tuple("whatever.property", null, "nothing.special", false) | |||
); | |||
} | |||
@Test | |||
public void migration_is_doing_nothing_when_no_data() throws SQLException { | |||
assertThat(db.countRowsOfTable("properties")).isEqualTo(0); | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("properties")).isEqualTo(0); | |||
} | |||
private void insertProperty(String propKey, @Nullable String textValue, @Nullable String clobValue, boolean isEmpty) { | |||
HashMap<String, Object> map = new HashMap<>(); | |||
map.put("PROP_KEY", propKey); | |||
map.put("TEXT_VALUE", textValue); | |||
map.put("CLOB_VALUE", clobValue); | |||
map.put("IS_EMPTY", isEmpty); | |||
db.executeInsert("PROPERTIES", map); | |||
} | |||
private void assertPropertyContainsInAnyOrder(Tuple... tuples) { | |||
assertThat(db.select(SELECT_PROPERTIES) | |||
.stream() | |||
.map(p -> new Tuple(p.get("PROP_KEY"), p.get("TEXT_VALUE"), p.get("CLOB_VALUE"), p.get("IS_EMPTY"))) | |||
.collect(Collectors.toList())) | |||
.containsExactlyInAnyOrder(tuples); | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
CREATE TABLE "PROPERTIES" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"PROP_KEY" VARCHAR(512) NOT NULL, | |||
"RESOURCE_ID" INTEGER, | |||
"USER_ID" INTEGER, | |||
"IS_EMPTY" BOOLEAN NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
"CLOB_VALUE" CLOB, | |||
"CREATED_AT" BIGINT | |||
); | |||
CREATE INDEX "PROPERTIES_KEY" ON "PROPERTIES" ("PROP_KEY"); | |||
@@ -2807,7 +2807,7 @@ onboarding.project_analysis.description=We initialized your project on {instance | |||
onboarding.project_analysis.commands_for_analysis=Below are the commands to use to do an analysis. | |||
onboarding.project_analysis.guide_to_integrate_pipelines=follow the guide to integrating with Pipelines | |||
onboarding.project_analysis.guide_to_integrate_travis=follow the guide to integrating with Travis CI | |||
onboarding.project_analysis.guide_to_integrate_vsts=follow the guide to integrating with VSTS | |||
onboarding.project_analysis.guide_to_integrate_vsts=follow the guide to integrating with Azure DevOps Services | |||
onboarding.project_analysis.simply_link=Simply {link}. | |||
onboarding.project_analysis.suggestions.bitbucket=If you are using Bitbucket Cloud Pipelines, the SonarCloud App makes it easier to run these commands with your CI process. | |||
onboarding.project_analysis.suggestions.github=If you are using Travis CI, the SonarCloud Travis Add-on makes it easier to run these commands with your CI process. |