Import approval right entities from Gerrit 1 into ProjectRight

The ProjectRight entity binds a single group to an ApprovalCategory,
and denotes what range of values within the ApprovalCategory can be
used by the members of that group.

Since Gerrit 1 supported individual users to be added to projects in
the approver, verifier or submitter category we create fake groups for
these cases and toss the other users into those groups.

The submitter category uses a position of -1, indicating that it should
not appear in the review status table of a change, but it still is a
valid category within the system.  This hack is necesary to reuse the
same ProjectRight system to handle the submitter status.

Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce
2009-01-03 14:00:31 -08:00
parent 68eff50909
commit a26dc96cf8
7 changed files with 473 additions and 8 deletions

View File

@@ -21,6 +21,7 @@ public class GerritConfig {
protected String canonicalUrl;
protected GitwebLink gitweb;
protected List<ApprovalType> approvalTypes;
protected List<ApprovalType> actionTypes;
protected int sshdPort;
public GerritConfig() {
@@ -43,8 +44,13 @@ public class GerritConfig {
}
public void add(final ApprovalType t) {
initApprovalTypes();
approvalTypes.add(t);
if (0 <= t.getCategory().getPosition()) {
initApprovalTypes();
approvalTypes.add(t);
} else {
initActionTypes();
actionTypes.add(t);
}
}
public List<ApprovalType> getApprovalTypes() {
@@ -58,6 +64,17 @@ public class GerritConfig {
}
}
public List<ApprovalType> getActionTypes() {
initActionTypes();
return actionTypes;
}
private void initActionTypes() {
if (actionTypes == null) {
actionTypes = new ArrayList<ApprovalType>();
}
}
public int getSshdPort() {
return sshdPort;
}

View File

@@ -0,0 +1,94 @@
// Copyright 2008 Google Inc.
//
// 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.client.reviewdb;
import com.google.gwtorm.client.Column;
import com.google.gwtorm.client.CompoundKey;
/** Grant to use an {@link ApprovalCategory} in the scope of a {@link Project}. */
public final class ProjectRight {
/** Project.Id meaning "any and all projects on this server". */
public static final Project.Id WILD_PROJECT = new Project.Id(0);
public static class Key extends CompoundKey<Project.Id> {
@Column
protected Project.Id projectId;
@Column
protected ApprovalCategory.Id categoryId;
@Column
protected AccountGroup.Id groupId;
protected Key() {
projectId = new Project.Id();
categoryId = new ApprovalCategory.Id();
groupId = new AccountGroup.Id();
}
public Key(final Project.Id p, final ApprovalCategory.Id a,
final AccountGroup.Id g) {
projectId = p;
categoryId = a;
groupId = g;
}
@Override
public Project.Id getParentKey() {
return projectId;
}
@Override
public com.google.gwtorm.client.Key<?>[] members() {
return new com.google.gwtorm.client.Key<?>[] {categoryId, groupId};
}
}
@Column(name = Column.NONE)
protected Key key;
@Column
protected short minValue;
@Column
protected short maxValue;
protected ProjectRight() {
}
public ProjectRight(final ProjectRight.Key k) {
key = k;
}
public ProjectRight.Key getKey() {
return key;
}
public short getMinValue() {
return minValue;
}
public void setMinValue(final short m) {
minValue = m;
}
public short getMaxValue() {
return maxValue;
}
public void setMaxValue(final short m) {
maxValue = m;
}
}

View File

@@ -0,0 +1,37 @@
// Copyright 2008 Google Inc.
//
// 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.client.reviewdb;
import com.google.gwtorm.client.Access;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.PrimaryKey;
import com.google.gwtorm.client.Query;
import com.google.gwtorm.client.ResultSet;
public interface ProjectRightAccess extends
Access<ProjectRight, ProjectRight.Key> {
@PrimaryKey("key")
ProjectRight get(ProjectRight.Key key) throws OrmException;
@Query("WHERE key.projectId = ?")
ResultSet<ProjectRight> byProject(Project.Id id) throws OrmException;
@Query("WHERE key.groupId = ?")
ResultSet<ProjectRight> byGroup(AccountGroup.Id id) throws OrmException;
@Query("WHERE key.categoryId = ?")
ResultSet<ProjectRight> byApprovalCategory(ApprovalCategory.Id id)
throws OrmException;
}

View File

@@ -59,6 +59,9 @@ public interface ReviewDb extends Schema {
@Relation
ProjectAccess projects();
@Relation
ProjectRightAccess projectRights();
@Relation
BranchAccess branches();

View File

@@ -0,0 +1,287 @@
// Copyright 2008 Google Inc.
//
// 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.pgm;
import com.google.gerrit.client.reviewdb.Account;
import com.google.gerrit.client.reviewdb.AccountGroup;
import com.google.gerrit.client.reviewdb.AccountGroupMember;
import com.google.gerrit.client.reviewdb.ApprovalCategory;
import com.google.gerrit.client.reviewdb.Change;
import com.google.gerrit.client.reviewdb.PatchSet;
import com.google.gerrit.client.reviewdb.Project;
import com.google.gerrit.client.reviewdb.ProjectRight;
import com.google.gerrit.client.reviewdb.ReviewDb;
import com.google.gerrit.client.reviewdb.SystemConfig;
import com.google.gerrit.git.InvalidRepositoryException;
import com.google.gerrit.git.PatchSetImporter;
import com.google.gerrit.server.GerritServer;
import com.google.gwtjsonrpc.server.XsrfException;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.jdbc.JdbcSchema;
import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.ProgressMonitor;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.lib.TextProgressMonitor;
import org.spearce.jgit.revwalk.RevCommit;
import org.spearce.jgit.revwalk.RevWalk;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Imports data from Gerrit 1 into Gerrit 2.
* <p>
* The tool assumes that <code>devutil/import_gerrit1.sql</code> has already
* been executed on this schema. All existing ProjectRight entities are wiped
* from the database and generated from scratch.
* <p>
* The tool requires Gerrit 1 tables (<code>gerrit1.$table_name</code>) through
* the same database connection as the ReviewDb schema is on.
*/
public class ImportGerrit1 {
private static GerritServer gs;
private static ReviewDb db;
private static Connection sql;
private static ApprovalCategory verifyCategory;
private static ApprovalCategory approveCategory;
private static ApprovalCategory submitCategory;
public static void main(final String[] argv) throws OrmException,
XsrfException, SQLException, IOException, InvalidRepositoryException {
final ProgressMonitor pm = new TextProgressMonitor();
gs = GerritServer.getInstance();
db = gs.getDatabase().open();
sql = ((JdbcSchema) db).getConnection();
try {
verifyCategory = db.approvalCategories().byName("Verified");
approveCategory = db.approvalCategories().byName("Code Review");
submitCategory = db.approvalCategories().byName("Submit");
final Statement query = sql.createStatement();
java.sql.ResultSet srcs;
// Convert the approval right data from projects.
//
pm.start(1);
pm.beginTask("Import project rights", ProgressMonitor.UNKNOWN);
query.executeUpdate("DELETE FROM project_rights");
insertApprovalWildCard();
srcs =
query.executeQuery("SELECT p.project_id, r.ar_key"
+ " FROM gerrit1.project_code_reviews r, projects p"
+ " WHERE p.project_id = r.project_id");
while (srcs.next()) {
final Project.Id projectId = new Project.Id(srcs.getInt(1));
final String arKey = srcs.getString(2);
doImport(projectId, arKey);
pm.update(1);
}
srcs.close();
pm.endTask();
// Rebuild the cached PatchSet information directly from Git.
// There's some oddities in the Gerrit 1 data that we got from
// Google App Engine's data store; the quickest way to fix it
// is to just recache the data from Git.
//
srcs =
query.executeQuery("SELECT change_id,patch_set_id FROM patch_sets");
final ArrayList<PatchSet.Id> psToDo = new ArrayList<PatchSet.Id>();
while (srcs.next()) {
final Change.Id changeId = new Change.Id(srcs.getInt(1));
final PatchSet.Id psId = new PatchSet.Id(changeId, srcs.getInt(2));
psToDo.add(psId);
}
query.close();
pm.start(1);
pm.beginTask("Import patch sets", psToDo.size());
for (final PatchSet.Id psId : psToDo) {
final Change c = db.changes().get(psId.getParentKey());
final PatchSet ps = db.patchSets().get(psId);
final String projectName = c.getDest().getParentKey().get();
final Repository repo = gs.getRepositoryCache().get(projectName);
final RevWalk rw = new RevWalk(repo);
final RevCommit src =
rw.parseCommit(ObjectId.fromString(ps.getRevision().get()));
new PatchSetImporter(db, repo, src, ps, false).run();
pm.update(1);
}
pm.endTask();
} finally {
db.close();
}
}
private static void insertApprovalWildCard() throws OrmException {
final ProjectRight.Key key =
new ProjectRight.Key(ProjectRight.WILD_PROJECT,
approveCategory.getId(), db.systemConfig().get(
new SystemConfig.Key()).registeredGroupId);
final ProjectRight pr = new ProjectRight(key);
pr.setMinValue((short) -1);
pr.setMaxValue((short) 1);
db.projectRights().insert(Collections.singleton(pr));
}
private static void doImport(final Project.Id projectId, final String arKey)
throws OrmException, SQLException {
final int arId = findId(arKey);
if (arId < 0) {
return;
}
final Project proj = db.projects().get(projectId);
final Set<AccountGroup.Id> approverg = groups(arId, "approver");
final Set<AccountGroup.Id> verifierg = groups(arId, "verifier");
final Set<AccountGroup.Id> submitterg = groups(arId, "submitter");
final Set<Account.Id> approveru = users(arId, "approver");
final Set<Account.Id> verifieru = users(arId, "verifier");
final Set<Account.Id> submitteru = users(arId, "submitter");
importCat(proj, "approvers", approveCategory, approverg, approveru);
importCat(proj, "verifiers", verifyCategory, verifierg, verifieru);
importCat(proj, "submitters", submitCategory, submitterg, submitteru);
}
private static void importCat(final Project proj, final String type,
final ApprovalCategory category, final Set<AccountGroup.Id> groups,
final Set<Account.Id> users) throws OrmException {
final HashSet<Account.Id> needGroup = new HashSet<Account.Id>(users);
for (final AccountGroup.Id groupId : groups) {
insertRight(proj, category, groupId);
for (final Iterator<Account.Id> i = needGroup.iterator(); i.hasNext();) {
if (gs.getGroupCache().isInGroup(i.next(), groupId)) {
i.remove();
}
}
}
if (!needGroup.isEmpty()) {
final AccountGroup.Id groupId =
new AccountGroup.Id(db.nextAccountGroupId());
final AccountGroup group =
new AccountGroup(new AccountGroup.NameKey(shortName(proj) + "_"
+ proj.getId().get() + "-" + type), groupId);
group.setOwnerGroupId(proj.getOwnerGroupId());
group.setDescription(proj.getName() + " " + type);
db.accountGroups().insert(Collections.singleton(group));
for (final Account.Id aId : needGroup) {
db.accountGroupMembers().insert(
Collections.singleton(new AccountGroupMember(
new AccountGroupMember.Key(aId, groupId))));
}
insertRight(proj, category, groupId);
}
}
private static void insertRight(final Project proj,
final ApprovalCategory category, final AccountGroup.Id groupId)
throws OrmException {
final ProjectRight.Key key =
new ProjectRight.Key(proj.getId(), category.getId(), groupId);
final ProjectRight pr = new ProjectRight(key);
pr.setMinValue(Short.MIN_VALUE);
pr.setMaxValue(Short.MAX_VALUE);
db.projectRights().insert(Collections.singleton(pr));
}
private static String shortName(final Project proj) {
final String n = proj.getName();
final int s = n.lastIndexOf('/');
return 0 < s ? n.substring(s + 1) : n;
}
private static Set<AccountGroup.Id> groups(final int arId, final String type)
throws SQLException {
final PreparedStatement ps =
sql.prepareStatement("SELECT g.group_id FROM account_groups g,"
+ " gerrit1.approval_right_groups s, gerrit1.account_groups o"
+ " WHERE s.ar_id = ? AND s.type = ?"
+ " AND o.gae_key = s.group_key AND (g.name = o.name"
+ " OR (g.name = 'Administrators' AND o.name = 'admin'))");
try {
ps.setInt(1, arId);
ps.setString(2, type);
final java.sql.ResultSet rs = ps.executeQuery();
try {
final HashSet<AccountGroup.Id> r = new HashSet<AccountGroup.Id>();
while (rs.next()) {
r.add(new AccountGroup.Id(rs.getInt(1)));
}
return r;
} finally {
rs.close();
}
} finally {
ps.close();
}
}
private static Set<Account.Id> users(final int arId, final String type)
throws SQLException {
final PreparedStatement ps =
sql.prepareStatement("SELECT a.account_id FROM accounts a,"
+ " gerrit1.approval_right_users s"
+ " WHERE s.ar_id = ? AND s.type = ?"
+ " AND a.preferred_email = s.email");
try {
ps.setInt(1, arId);
ps.setString(2, type);
final java.sql.ResultSet rs = ps.executeQuery();
try {
final HashSet<Account.Id> r = new HashSet<Account.Id>();
while (rs.next()) {
r.add(new Account.Id(rs.getInt(1)));
}
return r;
} finally {
rs.close();
}
} finally {
ps.close();
}
}
private static int findId(final String arKey) throws SQLException {
final PreparedStatement ps =
sql.prepareStatement("SELECT ar_id FROM gerrit1.approval_rights"
+ " WHERE gae_key=?");
try {
ps.setString(1, arKey);
final java.sql.ResultSet rs = ps.executeQuery();
try {
if (rs.next()) {
return rs.getInt(1);
}
return -1;
} finally {
rs.close();
}
} finally {
ps.close();
}
}
}

View File

@@ -216,6 +216,20 @@ public class GerritServer {
txn.commit();
}
private void initSubmitCategory(final ReviewDb c) throws OrmException {
final Transaction txn = c.beginTransaction();
final ApprovalCategory cat;
final ArrayList<ApprovalCategoryValue> vals;
cat = new ApprovalCategory(new ApprovalCategory.Id("SUBM"), "Submit");
cat.setPosition((short) -1);
vals = new ArrayList<ApprovalCategoryValue>();
vals.add(value(cat, 1, "Submit"));
c.approvalCategories().insert(Collections.singleton(cat), txn);
c.approvalCategoryValues().insert(vals);
txn.commit();
}
private static ApprovalCategoryValue value(final ApprovalCategory cat,
final int value, final String name) {
return new ApprovalCategoryValue(new ApprovalCategoryValue.Id(cat.getId(),
@@ -241,6 +255,7 @@ public class GerritServer {
initSystemConfig(c);
initVerifiedCategory(c);
initCodeReviewCategory(c);
initSubmitCategory(c);
sConfig = c.systemConfig().get(new SystemConfig.Key());
}

View File

@@ -6,20 +6,24 @@
-- pg_dump $srcdb | psql $dstdb
-- psql -f devutil/import_gerrit1.sql $dstdb
--
-- Run the ALTER commands displayed in a psql prompt.
-- Launch Gerrit 2 once to create the database schema.
-- Terminate it once the schema has constructed.
--
-- Ensure the Git repositories are where git_base_path in the
-- system_config table says they should be.
--
-- Create a GerritServer.properties file for your database.
--
-- Run this from your shell:
-- Ensure the GRANTs at the end of this script were run for
-- the user listed in GerritServer.properties.
--
-- make release
-- psql $dstdb -tAc 'select change_id,patch_set_id from patch_sets' \
-- | release/bin/gerrit2.sh \
-- Execute this from your shell:
--
-- cd appdist && \
-- mvn package && \
-- target/gerrit-2.*/gerrit-2.*/bin/gerrit2.sh \
-- --config=GerritServer.properties \
-- ReimportPatchSets
-- ImportGerrit1
--
DELETE FROM accounts;
@@ -691,3 +695,11 @@ WHERE
SELECT setval('change_id',(SELECT MAX(change_id) FROM changes));
-- contributor_agreement_id (above)
SELECT setval('project_id',(SELECT MAX(project_id) FROM projects));
-- Grant access to read tables needed for import
--
GRANT SELECT ON gerrit1.project_code_reviews TO gerrit2;
GRANT SELECT ON gerrit1.approval_right_groups TO gerrit2;
GRANT SELECT ON gerrit1.approval_right_users TO gerrit2;
GRANT SELECT ON gerrit1.approval_rights TO gerrit2;
GRANT SELECT ON gerrit1.account_groups TO gerrit2;