// Copyright (C) 2009 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 com.google.gerrit.reviewdb.AccountGroup; import com.google.gerrit.reviewdb.AccountGroupName; import com.google.gerrit.reviewdb.ApprovalCategory; import com.google.gerrit.reviewdb.ApprovalCategoryValue; import com.google.gerrit.reviewdb.CurrentSchemaVersion; import com.google.gerrit.reviewdb.Project; import com.google.gerrit.reviewdb.RefRight; import com.google.gerrit.reviewdb.ReviewDb; import com.google.gerrit.reviewdb.SystemConfig; import com.google.gerrit.server.config.SitePath; import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.workflow.NoOpFunction; import com.google.gerrit.server.workflow.SubmitFunction; import com.google.gwtjsonrpc.server.SignedToken; import com.google.gwtorm.client.OrmException; import com.google.gwtorm.jdbc.JdbcExecutor; import com.google.gwtorm.jdbc.JdbcSchema; import com.google.gwtorm.schema.sql.DialectH2; import com.google.gwtorm.schema.sql.DialectMySQL; import com.google.gwtorm.schema.sql.DialectPostgreSQL; import com.google.gwtorm.schema.sql.SqlDialect; import com.google.inject.Inject; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; /** Creates the current database schema and populates initial code rows. */ public class SchemaCreator { private static final Project.NameKey DEFAULT_WILD_NAME = new Project.NameKey("-- All Projects --"); private final @SitePath File site_path; private final int versionNbr; private final ScriptRunner index_generic; private final ScriptRunner index_postgres; private final ScriptRunner mysql_nextval; @Inject public SchemaCreator(final SitePaths site, @Current final SchemaVersion version) { this(site.site_path, version); } public SchemaCreator(final @SitePath File site, @Current final SchemaVersion version) { site_path = site; versionNbr = version.getVersionNbr(); index_generic = new ScriptRunner("index_generic.sql"); index_postgres = new ScriptRunner("index_postgres.sql"); mysql_nextval = new ScriptRunner("mysql_nextval.sql"); } public void create(final ReviewDb db) throws OrmException { final JdbcSchema jdbc = (JdbcSchema) db; final JdbcExecutor e = new JdbcExecutor(jdbc); try { jdbc.updateSchema(e); } finally { e.close(); } final CurrentSchemaVersion sVer = CurrentSchemaVersion.create(); sVer.versionNbr = versionNbr; db.schemaVersion().insert(Collections.singleton(sVer)); final SystemConfig sConfig = initSystemConfig(db); initOwnerCategory(db); initReadCategory(db, sConfig); initVerifiedCategory(db); initCodeReviewCategory(db, sConfig); initSubmitCategory(db); initPushTagCategory(db); initPushUpdateBranchCategory(db); initForgeIdentityCategory(db, sConfig); initWildCardProject(db); final SqlDialect d = jdbc.getDialect(); if (d instanceof DialectH2) { index_generic.run(db); } else if (d instanceof DialectMySQL) { index_generic.run(db); mysql_nextval.run(db); } else if (d instanceof DialectPostgreSQL) { index_postgres.run(db); } else { throw new OrmException("Unsupported database " + d.getClass().getName()); } } private SystemConfig initSystemConfig(final ReviewDb c) throws OrmException { final AccountGroup admin = new AccountGroup(new AccountGroup.NameKey("Administrators"), new AccountGroup.Id(c.nextAccountGroupId())); admin.setDescription("Gerrit Site Administrators"); admin.setType(AccountGroup.Type.INTERNAL); c.accountGroups().insert(Collections.singleton(admin)); c.accountGroupNames().insert( Collections.singleton(new AccountGroupName(admin))); final AccountGroup anonymous = new AccountGroup(new AccountGroup.NameKey("Anonymous Users"), new AccountGroup.Id(c.nextAccountGroupId())); anonymous.setDescription("Any user, signed-in or not"); anonymous.setOwnerGroupId(admin.getId()); anonymous.setType(AccountGroup.Type.SYSTEM); c.accountGroups().insert(Collections.singleton(anonymous)); c.accountGroupNames().insert( Collections.singleton(new AccountGroupName(anonymous))); final AccountGroup registered = new AccountGroup(new AccountGroup.NameKey("Registered Users"), new AccountGroup.Id(c.nextAccountGroupId())); registered.setDescription("Any signed-in user"); registered.setOwnerGroupId(admin.getId()); registered.setType(AccountGroup.Type.SYSTEM); c.accountGroups().insert(Collections.singleton(registered)); c.accountGroupNames().insert( Collections.singleton(new AccountGroupName(registered))); final AccountGroup batchUsers = new AccountGroup(new AccountGroup.NameKey("Non-Interactive Users"), new AccountGroup.Id(c.nextAccountGroupId())); batchUsers.setDescription("Users who perform batch actions on Gerrit"); batchUsers.setOwnerGroupId(admin.getId()); batchUsers.setType(AccountGroup.Type.INTERNAL); c.accountGroups().insert(Collections.singleton(batchUsers)); c.accountGroupNames().insert( Collections.singleton(new AccountGroupName(batchUsers))); final AccountGroup owners = new AccountGroup(new AccountGroup.NameKey("Project Owners"), new AccountGroup.Id(c.nextAccountGroupId())); owners.setDescription("Any owner of the project"); owners.setOwnerGroupId(admin.getId()); owners.setType(AccountGroup.Type.SYSTEM); c.accountGroups().insert(Collections.singleton(owners)); c.accountGroupNames().insert( Collections.singleton(new AccountGroupName(owners))); final SystemConfig s = SystemConfig.create(); s.registerEmailPrivateKey = SignedToken.generateRandomKey(); s.adminGroupId = admin.getId(); s.anonymousGroupId = anonymous.getId(); s.registeredGroupId = registered.getId(); s.batchUsersGroupId = batchUsers.getId(); s.ownerGroupId = owners.getId(); s.wildProjectName = DEFAULT_WILD_NAME; try { s.sitePath = site_path.getCanonicalPath(); } catch (IOException e) { s.sitePath = site_path.getAbsolutePath(); } c.systemConfig().insert(Collections.singleton(s)); return s; } private void initWildCardProject(final ReviewDb c) throws OrmException { final Project p; p = new Project(DEFAULT_WILD_NAME); p.setDescription("Rights inherited by all other projects"); p.setUseContributorAgreements(false); c.projects().insert(Collections.singleton(p)); } private void initVerifiedCategory(final ReviewDb c) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> vals; cat = new ApprovalCategory(new ApprovalCategory.Id("VRIF"), "Verified"); cat.setPosition((short) 0); cat.setAbbreviatedName("V"); vals = new ArrayList<ApprovalCategoryValue>(); vals.add(value(cat, 1, "Verified")); vals.add(value(cat, 0, "No score")); vals.add(value(cat, -1, "Fails")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(vals); } private void initCodeReviewCategory(final ReviewDb c, final SystemConfig sConfig) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> vals; cat = new ApprovalCategory(new ApprovalCategory.Id("CRVW"), "Code Review"); cat.setPosition((short) 1); cat.setAbbreviatedName("R"); cat.setCopyMinScore(true); vals = new ArrayList<ApprovalCategoryValue>(); vals.add(value(cat, 2, "Looks good to me, approved")); vals.add(value(cat, 1, "Looks good to me, but someone else must approve")); vals.add(value(cat, 0, "No score")); vals.add(value(cat, -1, "I would prefer that you didn't submit this")); vals.add(value(cat, -2, "Do not submit")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(vals); final RefRight approve = new RefRight(new RefRight.Key(DEFAULT_WILD_NAME, new RefRight.RefPattern("refs/heads/*"), cat.getId(), sConfig.registeredGroupId)); approve.setMaxValue((short) 1); approve.setMinValue((short) -1); c.refRights().insert(Collections.singleton(approve)); } private void initOwnerCategory(final ReviewDb c) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> vals; cat = new ApprovalCategory(ApprovalCategory.OWN, "Owner"); cat.setPosition((short) -1); cat.setFunctionName(NoOpFunction.NAME); vals = new ArrayList<ApprovalCategoryValue>(); vals.add(value(cat, 1, "Administer All Settings")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(vals); } private void initReadCategory(final ReviewDb c, final SystemConfig sConfig) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> vals; cat = new ApprovalCategory(ApprovalCategory.READ, "Read Access"); cat.setPosition((short) -1); cat.setFunctionName(NoOpFunction.NAME); vals = new ArrayList<ApprovalCategoryValue>(); vals.add(value(cat, 2, "Upload permission")); vals.add(value(cat, 1, "Read access")); vals.add(value(cat, -1, "No access")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(vals); final RefRight.RefPattern pattern = new RefRight.RefPattern(RefRight.ALL); { final RefRight read = new RefRight(new RefRight.Key(DEFAULT_WILD_NAME, pattern, cat.getId(), sConfig.anonymousGroupId)); read.setMaxValue((short) 1); read.setMinValue((short) 1); c.refRights().insert(Collections.singleton(read)); } { final RefRight read = new RefRight(new RefRight.Key(DEFAULT_WILD_NAME, pattern, cat.getId(), sConfig.registeredGroupId)); read.setMaxValue((short) 2); read.setMinValue((short) 1); c.refRights().insert(Collections.singleton(read)); } { final RefRight read = new RefRight(new RefRight.Key(DEFAULT_WILD_NAME, pattern, cat.getId(), sConfig.adminGroupId)); read.setMaxValue((short) 1); read.setMinValue((short) 1); c.refRights().insert(Collections.singleton(read)); } } private void initSubmitCategory(final ReviewDb c) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> vals; cat = new ApprovalCategory(ApprovalCategory.SUBMIT, "Submit"); cat.setPosition((short) -1); cat.setFunctionName(SubmitFunction.NAME); vals = new ArrayList<ApprovalCategoryValue>(); vals.add(value(cat, 1, "Submit")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(vals); } private void initPushTagCategory(final ReviewDb c) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> vals; cat = new ApprovalCategory(ApprovalCategory.PUSH_TAG, "Push Tag"); cat.setPosition((short) -1); cat.setFunctionName(NoOpFunction.NAME); vals = new ArrayList<ApprovalCategoryValue>(); vals.add(value(cat, ApprovalCategory.PUSH_TAG_SIGNED, "Create Signed Tag")); vals.add(value(cat, ApprovalCategory.PUSH_TAG_ANNOTATED, "Create Annotated Tag")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(vals); } private void initPushUpdateBranchCategory(final ReviewDb c) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> vals; cat = new ApprovalCategory(ApprovalCategory.PUSH_HEAD, "Push Branch"); cat.setPosition((short) -1); cat.setFunctionName(NoOpFunction.NAME); vals = new ArrayList<ApprovalCategoryValue>(); vals.add(value(cat, ApprovalCategory.PUSH_HEAD_UPDATE, "Update Branch")); vals.add(value(cat, ApprovalCategory.PUSH_HEAD_CREATE, "Create Branch")); vals.add(value(cat, ApprovalCategory.PUSH_HEAD_REPLACE, "Force Push Branch; Delete Branch")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(vals); } private void initForgeIdentityCategory(final ReviewDb c, final SystemConfig sConfig) throws OrmException { final ApprovalCategory cat; final ArrayList<ApprovalCategoryValue> values; cat = new ApprovalCategory(ApprovalCategory.FORGE_IDENTITY, "Forge Identity"); cat.setPosition((short) -1); cat.setFunctionName(NoOpFunction.NAME); values = new ArrayList<ApprovalCategoryValue>(); values.add(value(cat, ApprovalCategory.FORGE_AUTHOR, "Forge Author Identity")); values.add(value(cat, ApprovalCategory.FORGE_COMMITTER, "Forge Committer or Tagger Identity")); values.add(value(cat, ApprovalCategory.FORGE_SERVER, "Forge Gerrit Code Review Server Identity")); c.approvalCategories().insert(Collections.singleton(cat)); c.approvalCategoryValues().insert(values); RefRight right = new RefRight(new RefRight.Key(sConfig.wildProjectName, new RefRight.RefPattern(RefRight.ALL), ApprovalCategory.FORGE_IDENTITY, sConfig.registeredGroupId)); right.setMinValue(ApprovalCategory.FORGE_AUTHOR); right.setMaxValue(ApprovalCategory.FORGE_AUTHOR); c.refRights().insert(Collections.singleton(right)); } private static ApprovalCategoryValue value(final ApprovalCategory cat, final int value, final String name) { return new ApprovalCategoryValue(new ApprovalCategoryValue.Id(cat.getId(), (short) value), name); } }