diff options
Diffstat (limited to 'java/com/google/gerrit/server/schema/Schema_139.java')
-rw-r--r-- | java/com/google/gerrit/server/schema/Schema_139.java | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/java/com/google/gerrit/server/schema/Schema_139.java b/java/com/google/gerrit/server/schema/Schema_139.java new file mode 100644 index 0000000000..cdde7e4b22 --- /dev/null +++ b/java/com/google/gerrit/server/schema/Schema_139.java @@ -0,0 +1,212 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.server.schema; + +import static com.google.common.base.Preconditions.checkState; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Strings; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.MultimapBuilder; +import com.google.gerrit.common.Nullable; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.GerritPersonIdent; +import com.google.gerrit.server.account.AccountConfig; +import com.google.gerrit.server.account.InternalAccountUpdate; +import com.google.gerrit.server.account.ProjectWatches.NotifyType; +import com.google.gerrit.server.account.ProjectWatches.ProjectWatchKey; +import com.google.gerrit.server.config.AllUsersName; +import com.google.gerrit.server.extensions.events.GitReferenceUpdated; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.git.meta.MetaDataUpdate; +import com.google.gwtorm.jdbc.JdbcSchema; +import com.google.gwtorm.server.OrmDuplicateKeyException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.Provider; +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.lib.BatchRefUpdate; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevWalk; + +public class Schema_139 extends SchemaVersion { + private static final String MSG = "Migrate project watches to git"; + + private final GitRepositoryManager repoManager; + private final AllUsersName allUsersName; + private final PersonIdent serverUser; + + @Inject + Schema_139( + Provider<Schema_138> prior, + GitRepositoryManager repoManager, + AllUsersName allUsersName, + @GerritPersonIdent PersonIdent serverUser) { + super(prior); + this.repoManager = repoManager; + this.allUsersName = allUsersName; + this.serverUser = serverUser; + } + + @Override + protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException, SQLException { + ListMultimap<Account.Id, ProjectWatch> imports = + MultimapBuilder.hashKeys().arrayListValues().build(); + try (Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); + ResultSet rs = + stmt.executeQuery( + "SELECT " + + "account_id, " + + "project_name, " + + "filter, " + + "notify_abandoned_changes, " + + "notify_all_comments, " + + "notify_new_changes, " + + "notify_new_patch_sets, " + + "notify_submitted_changes " + + "FROM account_project_watches")) { + while (rs.next()) { + Account.Id accountId = new Account.Id(rs.getInt(1)); + ProjectWatch.Builder b = + ProjectWatch.builder() + .project(new Project.NameKey(rs.getString(2))) + .filter(rs.getString(3)) + .notifyAbandonedChanges(toBoolean(rs.getString(4))) + .notifyAllComments(toBoolean(rs.getString(5))) + .notifyNewChanges(toBoolean(rs.getString(6))) + .notifyNewPatchSets(toBoolean(rs.getString(7))) + .notifySubmittedChanges(toBoolean(rs.getString(8))); + imports.put(accountId, b.build()); + } + } + + if (imports.isEmpty()) { + return; + } + + try (Repository git = repoManager.openRepository(allUsersName); + RevWalk rw = new RevWalk(git)) { + BatchRefUpdate bru = git.getRefDatabase().newBatchUpdate(); + bru.setRefLogIdent(serverUser); + bru.setRefLogMessage(MSG, false); + + for (Map.Entry<Account.Id, Collection<ProjectWatch>> e : imports.asMap().entrySet()) { + Map<ProjectWatchKey, Set<NotifyType>> projectWatches = new HashMap<>(); + for (ProjectWatch projectWatch : e.getValue()) { + ProjectWatchKey key = + ProjectWatchKey.create(projectWatch.project(), projectWatch.filter()); + if (projectWatches.containsKey(key)) { + throw new OrmDuplicateKeyException( + "Duplicate key for watched project: " + key.toString()); + } + Set<NotifyType> notifyValues = EnumSet.noneOf(NotifyType.class); + if (projectWatch.notifyAbandonedChanges()) { + notifyValues.add(NotifyType.ABANDONED_CHANGES); + } + if (projectWatch.notifyAllComments()) { + notifyValues.add(NotifyType.ALL_COMMENTS); + } + if (projectWatch.notifyNewChanges()) { + notifyValues.add(NotifyType.NEW_CHANGES); + } + if (projectWatch.notifyNewPatchSets()) { + notifyValues.add(NotifyType.NEW_PATCHSETS); + } + if (projectWatch.notifySubmittedChanges()) { + notifyValues.add(NotifyType.SUBMITTED_CHANGES); + } + projectWatches.put(key, notifyValues); + } + + try (MetaDataUpdate md = + new MetaDataUpdate(GitReferenceUpdated.DISABLED, allUsersName, git, bru)) { + md.getCommitBuilder().setAuthor(serverUser); + md.getCommitBuilder().setCommitter(serverUser); + md.setMessage(MSG); + + AccountConfig accountConfig = new AccountConfig(e.getKey(), allUsersName, git); + accountConfig.load(md); + accountConfig.setAccountUpdate( + InternalAccountUpdate.builder() + .deleteProjectWatches(accountConfig.getProjectWatches().keySet()) + .updateProjectWatches(projectWatches) + .build()); + accountConfig.commit(md); + } + } + bru.execute(rw, NullProgressMonitor.INSTANCE); + } catch (IOException | ConfigInvalidException ex) { + throw new OrmException(ex); + } + } + + @AutoValue + abstract static class ProjectWatch { + abstract Project.NameKey project(); + + abstract @Nullable String filter(); + + abstract boolean notifyAbandonedChanges(); + + abstract boolean notifyAllComments(); + + abstract boolean notifyNewChanges(); + + abstract boolean notifyNewPatchSets(); + + abstract boolean notifySubmittedChanges(); + + static Builder builder() { + return new AutoValue_Schema_139_ProjectWatch.Builder(); + } + + @AutoValue.Builder + abstract static class Builder { + abstract Builder project(Project.NameKey project); + + abstract Builder filter(@Nullable String filter); + + abstract Builder notifyAbandonedChanges(boolean notifyAbandonedChanges); + + abstract Builder notifyAllComments(boolean notifyAllComments); + + abstract Builder notifyNewChanges(boolean notifyNewChanges); + + abstract Builder notifyNewPatchSets(boolean notifyNewPatchSets); + + abstract Builder notifySubmittedChanges(boolean notifySubmittedChanges); + + abstract ProjectWatch build(); + } + } + + private static boolean toBoolean(String v) { + checkState(!Strings.isNullOrEmpty(v)); + return v.equals("Y"); + } +} |