Create project refactoring

This refactoring is a preparation to feature
'Create project through web interface' which
includes a new UI to create projects.

It splits out the create project code
adding new classes that will be used both
by ssh command and the new UI.

Updated some naming pattern to keep it more
consistent.

Improved the exception handling.

Change-Id: I789c9a09f905d90680cc74d9b6aa7ae8f4d808b7
This commit is contained in:
monica.dionisio
2011-07-12 09:57:07 -03:00
committed by Gustaf Lundh
parent a3f73aab40
commit 860ea72aab
7 changed files with 490 additions and 310 deletions

View File

@@ -0,0 +1,29 @@
// Copyright (C) 2011 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.common.errors;
/** Error indicating failed to create new project. */
public class ProjectCreationFailedException extends Exception {
private static final long serialVersionUID = 1L;
public ProjectCreationFailedException(final String message) {
this(message, null);
}
public ProjectCreationFailedException(final String message,
final Throwable why) {
super(message, why);
}
}

View File

@@ -45,6 +45,7 @@ import com.google.gerrit.server.patch.AddReviewer;
import com.google.gerrit.server.patch.PublishComments;
import com.google.gerrit.server.patch.RemoveReviewer;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.CreateProject;
import com.google.gerrit.server.project.PerRequestProjectControlCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
@@ -95,5 +96,6 @@ public class GerritRequestModule extends FactoryModule {
factory(VisibleGroups.Factory.class);
factory(GroupDetailFactory.Factory.class);
factory(GroupMembers.Factory.class);
factory(CreateProject.Factory.class);
}
}

View File

@@ -0,0 +1,264 @@
// Copyright (C) 2011 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.project;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.errors.ProjectCreationFailedException;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.ProjectOwnerGroups;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.gerrit.server.project.ProjectCache;
/** Common class that holds the code to create projects */
public class CreateProject {
private static final Logger log = LoggerFactory
.getLogger(CreateProject.class);
public interface Factory {
CreateProject create(CreateProjectArgs createProjectArgs);
}
private final Set<AccountGroup.UUID> projectOwnerGroups;
private final IdentifiedUser currentUser;
private final GitRepositoryManager repoManager;
private final ReplicationQueue replication;
private final PersonIdent serverIdent;
private CreateProjectArgs createProjectArgs;
private ProjectCache projectCache;
private GroupCache groupCache;
private MetaDataUpdate.User metaDataUpdateFactory;
@Inject
CreateProject(@ProjectOwnerGroups Set<AccountGroup.UUID> pOwnerGroups,
IdentifiedUser identifiedUser, GitRepositoryManager gitRepoManager,
ReplicationQueue replicateq, ReviewDb db,
@GerritPersonIdent PersonIdent personIdent, final GroupCache groupCache,
final MetaDataUpdate.User metaDataUpdateFactory,
@Assisted CreateProjectArgs createPArgs, ProjectCache pCache) {
this.projectOwnerGroups = pOwnerGroups;
this.currentUser = identifiedUser;
this.repoManager = gitRepoManager;
this.replication = replicateq;
this.serverIdent = personIdent;
this.createProjectArgs = createPArgs;
this.projectCache = pCache;
this.groupCache = groupCache;
this.metaDataUpdateFactory = metaDataUpdateFactory;
}
public void createProject() throws ProjectCreationFailedException {
validateParameters();
try {
final Project.NameKey nameKey = createProjectArgs.getProject();
final String head =
createProjectArgs.permissionsOnly ? GitRepositoryManager.REF_CONFIG
: createProjectArgs.branch;
final Repository repo = repoManager.createRepository(nameKey);
try {
replication.replicateNewProject(nameKey, head);
final RefUpdate u = repo.updateRef(Constants.HEAD);
u.disableRefLog();
u.link(head);
createProjectConfig();
if (!createProjectArgs.permissionsOnly
&& createProjectArgs.createEmptyCommit) {
createEmptyCommit(repo, nameKey, createProjectArgs.branch);
}
} finally {
repo.close();
}
} catch (IllegalStateException e) {
handleRepositoryExistsException(createProjectArgs.getProject(), e);
} catch (RepositoryCaseMismatchException ee) {
handleRepositoryExistsException(ee.getNameOfExistingProject(), ee);
} catch (Exception e) {
final String msg = "Cannot create " + createProjectArgs.getProject();
log.error(msg, e);
throw new ProjectCreationFailedException(msg, e);
}
}
private void createProjectConfig() throws IOException, ConfigInvalidException {
final MetaDataUpdate md =
metaDataUpdateFactory.create(createProjectArgs.getProject());
try {
final ProjectConfig config = ProjectConfig.read(md);
config.load(md);
Project newProject = config.getProject();
newProject.setDescription(createProjectArgs.projectDescription);
newProject.setSubmitType(createProjectArgs.submitType);
newProject
.setUseContributorAgreements(createProjectArgs.contributorAgreements);
newProject.setUseSignedOffBy(createProjectArgs.signedOffBy);
newProject.setUseContentMerge(createProjectArgs.contentMerge);
newProject.setRequireChangeID(createProjectArgs.changeIdRequired);
if (createProjectArgs.newParent != null) {
newProject.setParentName(createProjectArgs.newParent.getProject()
.getNameKey());
}
if (!createProjectArgs.ownerIds.isEmpty()) {
final AccessSection all =
config.getAccessSection(AccessSection.ALL, true);
for (AccountGroup.UUID ownerId : createProjectArgs.ownerIds) {
AccountGroup accountGroup = groupCache.get(ownerId);
GroupReference group = config.resolve(accountGroup);
all.getPermission(Permission.OWNER, true).add(
new PermissionRule(group));
}
}
md.setMessage("Created project\n");
if (!config.commit(md)) {
throw new IOException("Cannot create "
+ createProjectArgs.getProjectName());
}
} finally {
md.close();
}
projectCache.onCreateProject(createProjectArgs.getProject());
repoManager.setProjectDescription(createProjectArgs.getProject(),
createProjectArgs.projectDescription);
replication.scheduleUpdate(createProjectArgs.getProject(),
GitRepositoryManager.REF_CONFIG);
}
private void validateParameters() throws ProjectCreationFailedException {
if (createProjectArgs.getProjectName() == null
|| createProjectArgs.getProjectName().isEmpty()) {
throw new ProjectCreationFailedException("Project name is required");
}
if (createProjectArgs.getProjectName().endsWith(Constants.DOT_GIT_EXT)) {
createProjectArgs.setProjectName(createProjectArgs.getProjectName()
.substring(
0,
createProjectArgs.getProjectName().length()
- Constants.DOT_GIT_EXT.length()));
}
if (!currentUser.getCapabilities().canCreateProject()) {
throw new ProjectCreationFailedException(String.format(
"%s does not have \"Create Project\" capability.",
currentUser.getUserName()));
}
if (createProjectArgs.ownerIds == null
|| createProjectArgs.ownerIds.isEmpty()) {
createProjectArgs.ownerIds =
new ArrayList<AccountGroup.UUID>(projectOwnerGroups);
}
while (createProjectArgs.branch.startsWith("/")) {
createProjectArgs.branch = createProjectArgs.branch.substring(1);
}
if (!createProjectArgs.branch.startsWith(Constants.R_HEADS)) {
createProjectArgs.branch = Constants.R_HEADS + createProjectArgs.branch;
}
if (!Repository.isValidRefName(createProjectArgs.branch)) {
throw new ProjectCreationFailedException(String.format(
"Branch \"%s\" is not a valid name.", createProjectArgs.branch));
}
}
private void createEmptyCommit(final Repository repo,
final Project.NameKey project, final String ref) throws IOException {
ObjectInserter oi = repo.newObjectInserter();
try {
CommitBuilder cb = new CommitBuilder();
cb.setTreeId(oi.insert(Constants.OBJ_TREE, new byte[] {}));
cb.setAuthor(metaDataUpdateFactory.getUserPersonIdent());
cb.setCommitter(serverIdent);
cb.setMessage("Initial empty repository\n");
ObjectId id = oi.insert(cb);
oi.flush();
RefUpdate ru = repo.updateRef(Constants.HEAD);
ru.setNewObjectId(id);
final Result result = ru.update();
switch (result) {
case NEW:
replication.scheduleUpdate(project, ref);
break;
default: {
throw new IOException(result.name());
}
}
} catch (IOException e) {
log.error(
"Cannot create empty commit for "
+ createProjectArgs.getProjectName(), e);
throw e;
} finally {
oi.release();
}
}
private void handleRepositoryExistsException(final Project.NameKey nameKey,
Exception e) throws ProjectCreationFailedException {
try {
Repository repo = repoManager.openRepository(nameKey);
try {
if (repo.getObjectDatabase().exists()) {
throw new ProjectCreationFailedException("Project \"" + nameKey
+ "\" exists", e);
}
} finally {
repo.close();
}
} catch (RepositoryNotFoundException er) {
throw new ProjectCreationFailedException("Cannot create \"" + nameKey
+ "\"", er);
}
}
}

View File

@@ -0,0 +1,56 @@
// Copyright (C) 2011 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.project;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.Project.SubmitType;
import java.util.List;
public class CreateProjectArgs {
private Project.NameKey projectName;
public List<AccountGroup.UUID> ownerIds;
public ProjectControl newParent;
public String projectDescription;
public SubmitType submitType;
public boolean contributorAgreements;
public boolean signedOffBy;
public boolean permissionsOnly;
public String branch;
public boolean contentMerge;
public boolean changeIdRequired;
public boolean createEmptyCommit;
public CreateProjectArgs() {
}
public Project.NameKey getProject() {
return projectName;
}
public String getProjectName() {
return projectName != null ? projectName.get() : null;
}
public void setProjectName(String n) {
projectName = n != null ? new Project.NameKey(n) : null;
}
public void setProjectName(Project.NameKey n) {
projectName = n;
}
}

View File

@@ -1,309 +0,0 @@
// 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.sshd.commands;
import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.reviewdb.Project.SubmitType;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.ProjectOwnerGroups;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.BaseCommand;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/** Create a new project. **/
final class CreateProject extends BaseCommand {
private static final Logger log = LoggerFactory.getLogger(CreateProject.class);
@Option(name = "--name", aliases = {"-n"}, metaVar = "NAME", usage = "name of project to be created (deprecated option)")
void setProjectNameFromOption(String name) {
if (projectName != null) {
throw new IllegalArgumentException("NAME already supplied");
} else {
projectName = name;
}
}
@Option(name = "--owner", aliases = {"-o"}, usage = "owner(s) of project")
private List<AccountGroup.UUID> ownerIds;
@Option(name = "--parent", aliases = {"-p"}, metaVar = "NAME", usage = "parent project")
private ProjectControl newParent;
@Option(name = "--permissions-only", usage = "create project for use only as parent")
private boolean permissionsOnly;
@Option(name = "--description", aliases = {"-d"}, metaVar = "DESCRIPTION", usage = "description of project")
private String projectDescription = "";
@Option(name = "--submit-type", aliases = {"-t"}, usage = "project submit type\n"
+ "(default: MERGE_IF_NECESSARY)")
private SubmitType submitType = SubmitType.MERGE_IF_NECESSARY;
@Option(name = "--use-contributor-agreements", aliases = {"--ca"}, usage = "if contributor agreement is required")
private boolean contributorAgreements;
@Option(name = "--use-signed-off-by", aliases = {"--so"}, usage = "if signed-off-by is required")
private boolean signedOffBy;
@Option(name = "--use-content-merge", usage = "allow automatic conflict resolving within files")
private boolean contentMerge;
@Option(name = "--require-change-id", aliases = {"--id"}, usage = "if change-id is required")
private boolean requireChangeID;
@Option(name = "--branch", aliases = {"-b"}, metaVar = "BRANCH", usage = "initial branch name\n"
+ "(default: master)")
private String branch = Constants.MASTER;
@Option(name = "--empty-commit", usage = "to create initial empty commit")
private boolean createEmptyCommit;
private String projectName;
@Argument(index = 0, metaVar="NAME", usage="name of project to be created")
void setProjectNameFromArgument(String name) {
if (projectName != null) {
throw new IllegalArgumentException("--name already supplied");
} else {
projectName = name;
}
}
@Inject
private GitRepositoryManager repoManager;
@Inject
private ProjectCache projectCache;
@Inject
private GroupCache groupCache;
@Inject
@ProjectOwnerGroups
private Set<AccountGroup.UUID> projectOwnerGroups;
@Inject
private IdentifiedUser currentUser;
@Inject
private ReplicationQueue rq;
@Inject
@GerritPersonIdent
private PersonIdent serverIdent;
@Inject
MetaDataUpdate.User metaDataUpdateFactory;
private Project.NameKey nameKey;
@Override
public void start(final Environment env) {
startThread(new CommandRunnable() {
@Override
public void run() throws Exception {
if (!currentUser.getCapabilities().canCreateProject()) {
String msg = String.format(
"fatal: %s does not have \"Create Project\" capability.",
currentUser.getUserName());
throw new UnloggedFailure(BaseCommand.STATUS_NOT_ADMIN, msg);
}
parseCommandLine();
validateParameters();
try {
nameKey = new Project.NameKey(projectName);
String head = permissionsOnly ? GitRepositoryManager.REF_CONFIG : branch;
final Repository repo = repoManager.createRepository(nameKey);
try {
rq.replicateNewProject(nameKey, head);
RefUpdate u = repo.updateRef(Constants.HEAD);
u.disableRefLog();
u.link(head);
createProjectConfig();
if (!permissionsOnly && createEmptyCommit) {
createEmptyCommit(repo, nameKey, branch);
}
} finally {
repo.close();
}
} catch (IllegalStateException err) {
handleRepositoryExistsException(nameKey);
} catch (RepositoryCaseMismatchException err) {
handleRepositoryExistsException(err.getNameOfExistingProject());
} catch (RepositoryNotFoundException badName) {
throw new UnloggedFailure(1, "fatal: " + badName.getMessage());
} catch (Exception err) {
throw new Failure(1, "fatal: Cannot create " + projectName, err);
}
}
});
}
private void createEmptyCommit(final Repository repo,
final Project.NameKey project, final String ref) throws IOException {
ObjectInserter oi = repo.newObjectInserter();
try {
CommitBuilder cb = new CommitBuilder();
cb.setTreeId(oi.insert(Constants.OBJ_TREE, new byte[] {}));
cb.setAuthor(metaDataUpdateFactory.getUserPersonIdent());
cb.setCommitter(serverIdent);
cb.setMessage("Initial empty repository\n");
ObjectId id = oi.insert(cb);
oi.flush();
RefUpdate ru = repo.updateRef(Constants.HEAD);
ru.setNewObjectId(id);
final Result result = ru.update();
switch (result) {
case NEW:
rq.scheduleUpdate(project, ref);
break;
default: {
throw new IOException(result.name());
}
}
} catch (IOException e) {
log.error("Cannot create empty commit for " + projectName, e);
throw e;
} finally {
oi.release();
}
}
private void createProjectConfig() throws IOException, ConfigInvalidException {
MetaDataUpdate md = metaDataUpdateFactory.create(nameKey);
try {
ProjectConfig config = ProjectConfig.read(md);
config.load(md);
Project newProject = config.getProject();
newProject.setDescription(projectDescription);
newProject.setSubmitType(submitType);
newProject.setUseContributorAgreements(contributorAgreements);
newProject.setUseSignedOffBy(signedOffBy);
newProject.setUseContentMerge(contentMerge);
newProject.setRequireChangeID(requireChangeID);
if (newParent != null) {
newProject.setParentName(newParent.getProject().getName());
}
if (!ownerIds.isEmpty()) {
AccessSection all = config.getAccessSection(AccessSection.ALL, true);
for (AccountGroup.UUID ownerId : ownerIds) {
AccountGroup accountGroup = groupCache.get(ownerId);
GroupReference group = config.resolve(accountGroup);
all.getPermission(Permission.OWNER, true).add(
new PermissionRule(group));
}
}
md.setMessage("Created project\n");
if (!config.commit(md)) {
throw new IOException("Cannot create " + projectName);
}
} finally {
md.close();
}
projectCache.onCreateProject(nameKey);
repoManager.setProjectDescription(nameKey, projectDescription);
rq.scheduleUpdate(nameKey, GitRepositoryManager.REF_CONFIG);
}
private void validateParameters() throws Failure {
if (projectName == null || projectName.isEmpty()) {
throw new Failure(1, "fatal: Argument NAME is required");
}
if (projectName.endsWith(Constants.DOT_GIT_EXT)) {
projectName = projectName.substring(0, //
projectName.length() - Constants.DOT_GIT_EXT.length());
}
if (ownerIds != null && !ownerIds.isEmpty()) {
ownerIds =
new ArrayList<AccountGroup.UUID>(new HashSet<AccountGroup.UUID>(ownerIds));
} else {
ownerIds = new ArrayList<AccountGroup.UUID>(projectOwnerGroups);
}
while (branch.startsWith("/")) {
branch = branch.substring(1);
}
if (!branch.startsWith(Constants.R_HEADS)) {
branch = Constants.R_HEADS + branch;
}
if (!Repository.isValidRefName(branch)) {
throw new Failure(1, "--branch \"" + branch + "\" is not a valid name");
}
}
private void handleRepositoryExistsException(final Project.NameKey projectName)
throws Failure {
try {
Repository repo = repoManager.openRepository(projectName);
try {
if (repo.getObjectDatabase().exists()) {
throw new UnloggedFailure(1, "fatal: project \"" + projectName
+ "\" exists");
}
} finally {
repo.close();
}
} catch (RepositoryNotFoundException err) {
throw new Failure(1, "fatal: Cannot create " + projectName, err);
}
}
}

View File

@@ -0,0 +1,138 @@
// 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.sshd.commands;
import com.google.gerrit.common.errors.ProjectCreationFailedException;
import com.google.gerrit.reviewdb.AccountGroup;
import com.google.gerrit.reviewdb.Project.SubmitType;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.project.CreateProject;
import com.google.gerrit.server.project.CreateProjectArgs;
import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.sshd.BaseCommand;
import com.google.inject.Inject;
import org.apache.sshd.server.Environment;
import org.eclipse.jgit.lib.Constants;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
import java.util.List;
/** Create a new project. **/
final class CreateProjectCommand extends BaseCommand {
@Option(name = "--name", aliases = {"-n"}, metaVar = "NAME", usage = "name of project to be created (deprecated option)")
void setProjectNameFromOption(String name) {
if (projectName != null) {
throw new IllegalArgumentException("NAME already supplied");
} else {
projectName = name;
}
}
@Option(name = "--owner", aliases = {"-o"}, usage = "owner(s) of project")
private List<AccountGroup.UUID> ownerIds;
@Option(name = "--parent", aliases = {"-p"}, metaVar = "NAME", usage = "parent project")
private ProjectControl newParent;
@Option(name = "--permissions-only", usage = "create project for use only as parent")
private boolean permissionsOnly;
@Option(name = "--description", aliases = {"-d"}, metaVar = "DESCRIPTION", usage = "description of project")
private String projectDescription = "";
@Option(name = "--submit-type", aliases = {"-t"}, usage = "project submit type\n"
+ "(default: MERGE_IF_NECESSARY)")
private SubmitType submitType = SubmitType.MERGE_IF_NECESSARY;
@Option(name = "--use-contributor-agreements", aliases = {"--ca"}, usage = "if contributor agreement is required")
private boolean contributorAgreements;
@Option(name = "--use-signed-off-by", aliases = {"--so"}, usage = "if signed-off-by is required")
private boolean signedOffBy;
@Option(name = "--use-content-merge", usage = "allow automatic conflict resolving within files")
private boolean contentMerge;
@Option(name = "--require-change-id", aliases = {"--id"}, usage = "if change-id is required")
private boolean requireChangeID;
@Option(name = "--branch", aliases = {"-b"}, metaVar = "BRANCH", usage = "initial branch name\n"
+ "(default: master)")
private String branch = Constants.MASTER;
@Option(name = "--empty-commit", usage = "to create initial empty commit")
private boolean createEmptyCommit;
private String projectName;
@Argument(index = 0, metaVar = "NAME", usage = "name of project to be created")
void setProjectNameFromArgument(String name) {
if (projectName != null) {
throw new IllegalArgumentException("--name already supplied");
} else {
projectName = name;
}
}
@Inject
private IdentifiedUser currentUser;
@Inject
private CreateProject.Factory CreateProjectFactory;
@Override
public void start(final Environment env) {
startThread(new CommandRunnable() {
@Override
public void run() throws Exception {
if (!currentUser.getCapabilities().canCreateProject()) {
String msg =
String.format(
"fatal: %s does not have \"Create Project\" capability.",
currentUser.getUserName());
throw new UnloggedFailure(BaseCommand.STATUS_NOT_ADMIN, msg);
}
parseCommandLine();
if (projectName == null) {
throw new UnloggedFailure(1, "fatal: Project name is required.");
}
try {
final CreateProjectArgs args = new CreateProjectArgs();
args.setProjectName(projectName);
args.ownerIds = ownerIds;
args.newParent = newParent;
args.permissionsOnly = permissionsOnly;
args.projectDescription = projectDescription;
args.submitType = submitType;
args.contributorAgreements = contributorAgreements;
args.signedOffBy = signedOffBy;
args.contentMerge = contentMerge;
args.changeIdRequired = requireChangeID;
args.branch = branch;
args.createEmptyCommit = createEmptyCommit;
final CreateProject createProject = CreateProjectFactory.create(args);
createProject.createProject();
} catch (ProjectCreationFailedException err) {
throw new UnloggedFailure(1, "fatal: " + err.getMessage(), err);
}
}
});
}
}

View File

@@ -29,7 +29,7 @@ public class MasterCommandModule extends CommandModule {
command(gerrit, "create-account").to(CreateAccountCommand.class);
command(gerrit, "create-group").to(CreateGroupCommand.class);
command(gerrit, "rename-group").to(RenameGroupCommand.class);
command(gerrit, "create-project").to(CreateProject.class);
command(gerrit, "create-project").to(CreateProjectCommand.class);
command(gerrit, "gsql").to(AdminQueryShell.class);
command(gerrit, "set-reviewers").to(SetReviewersCommand.class);
command(gerrit, "receive-pack").to(Receive.class);