Search in sources :

Example 36 with ProjectState

use of com.google.gerrit.server.project.ProjectState in project gerrit by GerritCodeReview.

the class ListProjects method display.

@Nullable
public SortedMap<String, ProjectInfo> display(@Nullable PrintWriter stdout) throws BadRequestException, PermissionBackendException {
    if (all && state != null) {
        throw new BadRequestException("'all' and 'state' may not be used together");
    }
    if (groupUuid != null) {
        try {
            if (!groupControlFactory.controlFor(groupUuid).isVisible()) {
                return Collections.emptySortedMap();
            }
        } catch (NoSuchGroupException ex) {
            return Collections.emptySortedMap();
        }
    }
    int foundIndex = 0;
    int found = 0;
    TreeMap<String, ProjectInfo> output = new TreeMap<>();
    Map<String, String> hiddenNames = new HashMap<>();
    Map<Project.NameKey, Boolean> accessibleParents = new HashMap<>();
    PermissionBackend.WithUser perm = permissionBackend.user(currentUser);
    final TreeMap<Project.NameKey, ProjectNode> treeMap = new TreeMap<>();
    try {
        Iterator<ProjectState> projectStatesIt = filter(perm).iterator();
        while (projectStatesIt.hasNext()) {
            ProjectState e = projectStatesIt.next();
            Project.NameKey projectName = e.getNameKey();
            if (e.getProject().getState() == HIDDEN && !all && state != HIDDEN) {
                // If state HIDDEN wasn't selected, and it's HIDDEN, pretend it's not present.
                continue;
            }
            if (state != null && e.getProject().getState() != state) {
                continue;
            }
            if (groupUuid != null && !e.getLocalGroups().contains(GroupReference.forGroup(groupResolver.parseId(groupUuid.get())))) {
                continue;
            }
            if (showTree && !format.isJson()) {
                treeMap.put(projectName, projectNodeFactory.create(e.getProject(), true));
                continue;
            }
            if (foundIndex++ < start) {
                continue;
            }
            if (limit > 0 && ++found > limit) {
                break;
            }
            ProjectInfo info = new ProjectInfo();
            info.name = projectName.get();
            if (showTree && format.isJson()) {
                addParentProjectInfo(hiddenNames, accessibleParents, perm, e, info);
            }
            if (showDescription) {
                info.description = emptyToNull(e.getProject().getDescription());
            }
            info.state = e.getProject().getState();
            try {
                if (!showBranch.isEmpty()) {
                    try (Repository git = repoManager.openRepository(projectName)) {
                        if (!type.matches(git)) {
                            continue;
                        }
                        List<Ref> refs = retrieveBranchRefs(e, git);
                        if (!hasValidRef(refs)) {
                            continue;
                        }
                        addProjectBranchesInfo(info, refs);
                    }
                } else if (!showTree && type.useMatch()) {
                    try (Repository git = repoManager.openRepository(projectName)) {
                        if (!type.matches(git)) {
                            continue;
                        }
                    }
                }
            } catch (RepositoryNotFoundException err) {
                // If the Git repository is gone, the project doesn't actually exist anymore.
                continue;
            } catch (IOException err) {
                logger.atWarning().withCause(err).log("Unexpected error reading %s", projectName);
                continue;
            }
            ImmutableList<WebLinkInfo> links = webLinks.getProjectLinks(projectName.get());
            info.webLinks = links.isEmpty() ? null : links;
            if (stdout == null || format.isJson()) {
                output.put(info.name, info);
                continue;
            }
            if (!showBranch.isEmpty()) {
                printProjectBranches(stdout, info);
            }
            stdout.print(info.name);
            if (info.description != null) {
                // We still want to list every project as one-liners, hence escaping \n.
                stdout.print(" - " + StringUtil.escapeString(info.description));
            }
            stdout.print('\n');
        }
        for (ProjectInfo info : output.values()) {
            info.id = Url.encode(info.name);
            info.name = null;
        }
        if (stdout == null) {
            return output;
        } else if (format.isJson()) {
            format.newGson().toJson(output, new TypeToken<Map<String, ProjectInfo>>() {
            }.getType(), stdout);
            stdout.print('\n');
        } else if (showTree && treeMap.size() > 0) {
            printProjectTree(stdout, treeMap);
        }
        return null;
    } finally {
        if (stdout != null) {
            stdout.flush();
        }
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) PermissionBackend(com.google.gerrit.server.permissions.PermissionBackend) NoSuchGroupException(com.google.gerrit.exceptions.NoSuchGroupException) ProjectInfo(com.google.gerrit.extensions.common.ProjectInfo) RepositoryNotFoundException(org.eclipse.jgit.errors.RepositoryNotFoundException) IOException(java.io.IOException) TreeMap(java.util.TreeMap) Project(com.google.gerrit.entities.Project) Repository(org.eclipse.jgit.lib.Repository) Ref(org.eclipse.jgit.lib.Ref) WebLinkInfo(com.google.gerrit.extensions.common.WebLinkInfo) BadRequestException(com.google.gerrit.extensions.restapi.BadRequestException) ProjectState(com.google.gerrit.server.project.ProjectState) Map(java.util.Map) SortedMap(java.util.SortedMap) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ImmutableSortedMap(com.google.common.collect.ImmutableSortedMap) TreeMap(java.util.TreeMap) Nullable(com.google.gerrit.common.Nullable)

Example 37 with ProjectState

use of com.google.gerrit.server.project.ProjectState in project gerrit by GerritCodeReview.

the class CherryPickChange method cherryPick.

/**
 * This function can be called directly to cherry-pick a change (or commit if sourceChange is
 * null) with a few other parameters that are especially useful for cherry-picking a commit that
 * is the revert-of another change.
 *
 * @param sourceChange Change to cherry pick. Can be null, and then the function will only cherry
 *     pick a commit.
 * @param project Project name
 * @param sourceCommit Id of the commit to be cherry picked.
 * @param input Input object for different configurations of cherry pick.
 * @param dest Destination branch for the cherry pick.
 * @param timestamp the current timestamp.
 * @param revertedChange The id of the change that is reverted. This is used for the "revertOf"
 *     field to mark the created cherry pick change as "revertOf" the original change that was
 *     reverted.
 * @param changeIdForNewChange The Change-Id that the new change of the cherry pick will have.
 * @param idForNewChange The ID that the new change of the cherry pick will have. If provided and
 *     the cherry-pick doesn't result in creating a new change, then
 *     InvalidChangeOperationException is thrown.
 * @return Result object that describes the cherry pick.
 * @throws IOException Unable to open repository or read from the database.
 * @throws InvalidChangeOperationException Parent or branch don't exist, or two changes with same
 *     key exist in the branch. Also thrown when idForNewChange is not null but cherry-pick only
 *     creates a new patchset rather than a new change.
 * @throws UpdateException Problem updating the database using batchUpdateFactory.
 * @throws RestApiException Error such as invalid SHA1
 * @throws ConfigInvalidException Can't find account to notify.
 * @throws NoSuchProjectException Can't find project state.
 */
public Result cherryPick(@Nullable Change sourceChange, Project.NameKey project, ObjectId sourceCommit, CherryPickInput input, BranchNameKey dest, Instant timestamp, @Nullable Change.Id revertedChange, @Nullable ObjectId changeIdForNewChange, @Nullable Change.Id idForNewChange, @Nullable Boolean workInProgress) throws IOException, InvalidChangeOperationException, UpdateException, RestApiException, ConfigInvalidException, NoSuchProjectException {
    IdentifiedUser identifiedUser = user.get();
    try (Repository git = gitManager.openRepository(project);
        // before patch sets are updated.
        ObjectInserter oi = git.newObjectInserter();
        ObjectReader reader = oi.newReader();
        CodeReviewRevWalk revWalk = CodeReviewCommit.newRevWalk(reader)) {
        Ref destRef = git.getRefDatabase().exactRef(dest.branch());
        if (destRef == null) {
            throw new InvalidChangeOperationException(String.format("Branch %s does not exist.", dest.branch()));
        }
        RevCommit baseCommit = getBaseCommit(destRef, project.get(), revWalk, input.base);
        CodeReviewCommit commitToCherryPick = revWalk.parseCommit(sourceCommit);
        if (input.parent <= 0 || input.parent > commitToCherryPick.getParentCount()) {
            throw new InvalidChangeOperationException(String.format("Cherry Pick: Parent %s does not exist. Please specify a parent in" + " range [1, %s].", input.parent, commitToCherryPick.getParentCount()));
        }
        // If the commit message is not set, the commit message of the source commit will be used.
        String commitMessage = Strings.nullToEmpty(input.message);
        commitMessage = commitMessage.isEmpty() ? commitToCherryPick.getFullMessage() : commitMessage;
        String destChangeId = getDestinationChangeId(commitMessage, changeIdForNewChange);
        ChangeData destChange = null;
        if (destChangeId != null) {
            // If "idForNewChange" is not null we must fail, since we are not expecting an already
            // existing change.
            destChange = getDestChangeWithVerification(destChangeId, dest, idForNewChange != null);
        }
        if (changeIdForNewChange != null) {
            // If Change-Id was explicitly provided for the new change, override the value in commit
            // message.
            commitMessage = ChangeIdUtil.insertId(commitMessage, changeIdForNewChange, true);
        } else if (destChangeId == null) {
            // If commit message did not specify Change-Id, generate a new one and insert to the
            // message.
            commitMessage = ChangeIdUtil.insertId(commitMessage, CommitMessageUtil.generateChangeId(), true);
        }
        commitMessage = CommitMessageUtil.checkAndSanitizeCommitMessage(commitMessage);
        CodeReviewCommit cherryPickCommit;
        ProjectState projectState = projectCache.get(dest.project()).orElseThrow(noSuchProject(dest.project()));
        PersonIdent committerIdent = identifiedUser.newCommitterIdent(timestamp, serverTimeZone);
        try {
            MergeUtil mergeUtil;
            if (input.allowConflicts) {
                // allowConflicts requires to use content merge
                mergeUtil = mergeUtilFactory.create(projectState, true);
            } else {
                // use content merge only if it's configured on the project
                mergeUtil = mergeUtilFactory.create(projectState);
            }
            cherryPickCommit = mergeUtil.createCherryPickFromCommit(oi, git.getConfig(), baseCommit, commitToCherryPick, committerIdent, commitMessage, revWalk, input.parent - 1, input.allowEmpty, input.allowConflicts);
            oi.flush();
        } catch (MergeIdenticalTreeException | MergeConflictException e) {
            throw new IntegrationConflictException("Cherry pick failed: " + e.getMessage(), e);
        }
        try (BatchUpdate bu = batchUpdateFactory.create(project, identifiedUser, timestamp)) {
            bu.setRepository(git, revWalk, oi);
            bu.setNotify(resolveNotify(input));
            Change.Id changeId;
            String newTopic = null;
            if (input.topic != null) {
                newTopic = Strings.emptyToNull(input.topic.trim());
            }
            if (newTopic == null && sourceChange != null && !Strings.isNullOrEmpty(sourceChange.getTopic())) {
                newTopic = sourceChange.getTopic() + "-" + dest.shortName();
            }
            if (destChange != null) {
                // The change key exists on the destination branch. The cherry pick
                // will be added as a new patch set.
                changeId = insertPatchSet(bu, git, destChange.notes(), cherryPickCommit, sourceChange, newTopic, input, workInProgress);
            } else {
                // Change key not found on destination branch. We can create a new
                // change.
                changeId = createNewChange(bu, cherryPickCommit, dest.branch(), newTopic, project, sourceChange, sourceCommit, input, revertedChange, idForNewChange, workInProgress);
            }
            bu.execute();
            return Result.create(changeId, cherryPickCommit.getFilesWithGitConflicts());
        }
    }
}
Also used : InvalidChangeOperationException(com.google.gerrit.server.project.InvalidChangeOperationException) CodeReviewRevWalk(com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk) Change(com.google.gerrit.entities.Change) IdentifiedUser(com.google.gerrit.server.IdentifiedUser) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) ChangeData(com.google.gerrit.server.query.change.ChangeData) MergeIdenticalTreeException(com.google.gerrit.server.submit.MergeIdenticalTreeException) BatchUpdate(com.google.gerrit.server.update.BatchUpdate) Repository(org.eclipse.jgit.lib.Repository) Ref(org.eclipse.jgit.lib.Ref) MergeConflictException(com.google.gerrit.extensions.restapi.MergeConflictException) ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) PersonIdent(org.eclipse.jgit.lib.PersonIdent) GerritPersonIdent(com.google.gerrit.server.GerritPersonIdent) MergeUtil(com.google.gerrit.server.git.MergeUtil) ObjectReader(org.eclipse.jgit.lib.ObjectReader) ProjectState(com.google.gerrit.server.project.ProjectState) IntegrationConflictException(com.google.gerrit.server.submit.IntegrationConflictException) RevCommit(org.eclipse.jgit.revwalk.RevCommit)

Example 38 with ProjectState

use of com.google.gerrit.server.project.ProjectState in project gerrit by GerritCodeReview.

the class CreateChange method checkAndSanitizeChangeInput.

/**
 * Checks and sanitizes the user input, e.g. check whether the input is legal; clean the input so
 * that it meets the requirement for creating a change; set a field based on the global configs,
 * etc.
 *
 * @param input the {@code ChangeInput} from the request. Note this method modify the {@code
 *     ChangeInput} object so that it can be reused directly by follow-up code.
 * @param me the user who sent the current request to create a change.
 * @throws BadRequestException if the input is not legal.
 */
private void checkAndSanitizeChangeInput(ChangeInput input, IdentifiedUser me) throws RestApiException, PermissionBackendException, IOException {
    if (Strings.isNullOrEmpty(input.branch)) {
        throw new BadRequestException("branch must be non-empty");
    }
    input.branch = RefNames.fullName(input.branch);
    if (!isBranchAllowed(input.branch)) {
        throw new BadRequestException("Cannot create a change on ref " + input.branch + ". Gerrit internal refs and refs/tags/* are not allowed.");
    }
    String subject = Strings.nullToEmpty(input.subject);
    subject = subject.replaceAll("(?m)^#.*$\n?", "").trim();
    if (subject.isEmpty()) {
        throw new BadRequestException("commit message must be non-empty");
    }
    input.subject = subject;
    Optional<String> changeId = getChangeIdFromMessage(input.subject);
    if (changeId.isPresent()) {
        if (!queryProvider.get().setLimit(1).byBranchKey(BranchNameKey.create(input.project, input.branch), Change.key(changeId.get())).isEmpty()) {
            throw new ResourceConflictException(String.format("A change with Change-Id %s already exists for this branch.", changeId.get()));
        }
    }
    if (input.topic != null) {
        input.topic = Strings.emptyToNull(input.topic.trim());
    }
    if (input.status != null && input.status != ChangeStatus.NEW) {
        throw new BadRequestException("unsupported change status");
    }
    if (input.baseChange != null && input.baseCommit != null) {
        throw new BadRequestException("only provide one of base_change or base_commit");
    }
    ProjectResource projectResource = projectsCollection.parse(input.project);
    // Checks whether the change to be created should be a private change.
    boolean privateByDefault = projectResource.getProjectState().is(BooleanProjectConfig.PRIVATE_BY_DEFAULT);
    boolean isPrivate = input.isPrivate == null ? privateByDefault : input.isPrivate;
    if (isPrivate && disablePrivateChanges) {
        throw new MethodNotAllowedException("private changes are disabled");
    }
    input.isPrivate = isPrivate;
    ProjectState projectState = projectResource.getProjectState();
    if (input.workInProgress == null) {
        if (projectState.is(BooleanProjectConfig.WORK_IN_PROGRESS_BY_DEFAULT)) {
            input.workInProgress = true;
        } else {
            input.workInProgress = firstNonNull(me.state().generalPreferences().workInProgressByDefault, false);
        }
    }
    if (input.merge != null) {
        if (!(submitType.equals(SubmitType.MERGE_ALWAYS) || submitType.equals(SubmitType.MERGE_IF_NECESSARY))) {
            throw new BadRequestException("Submit type: " + submitType + " is not supported");
        }
    }
    if (input.author != null && (Strings.isNullOrEmpty(input.author.email) || Strings.isNullOrEmpty(input.author.name))) {
        throw new BadRequestException("Author must specify name and email");
    }
}
Also used : ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) MethodNotAllowedException(com.google.gerrit.extensions.restapi.MethodNotAllowedException) BadRequestException(com.google.gerrit.extensions.restapi.BadRequestException) ProjectResource(com.google.gerrit.server.project.ProjectResource) ProjectState(com.google.gerrit.server.project.ProjectState)

Example 39 with ProjectState

use of com.google.gerrit.server.project.ProjectState in project gerrit by GerritCodeReview.

the class GetDiff method apply.

@Override
public Response<DiffInfo> apply(FileResource resource) throws BadRequestException, ResourceConflictException, ResourceNotFoundException, AuthException, InvalidChangeOperationException, IOException, PermissionBackendException {
    DiffPreferencesInfo prefs = new DiffPreferencesInfo();
    if (whitespace != null) {
        prefs.ignoreWhitespace = whitespace;
    } else if (ignoreWhitespace != null) {
        prefs.ignoreWhitespace = ignoreWhitespace.whitespace;
    } else {
        prefs.ignoreWhitespace = Whitespace.IGNORE_LEADING_AND_TRAILING;
    }
    prefs.intralineDifference = intraline;
    logger.atFine().log("diff preferences: ignoreWhitespace = %s, intralineDifference = %s", prefs.ignoreWhitespace, prefs.intralineDifference);
    PatchScriptFactory psf;
    PatchSet basePatchSet = null;
    PatchSet.Id pId = resource.getPatchKey().patchSetId();
    String fileName = resource.getPatchKey().fileName();
    logger.atFine().log("patchSetId = %d, fileName = %s, base = %s, parentNum = %d", pId.get(), fileName, base, parentNum);
    ChangeNotes notes = resource.getRevision().getNotes();
    if (base != null) {
        RevisionResource baseResource = revisions.parse(resource.getRevision().getChangeResource(), IdString.fromDecoded(base));
        basePatchSet = baseResource.getPatchSet();
        if (basePatchSet.id().get() == 0) {
            throw new BadRequestException("edit not allowed as base");
        }
        psf = patchScriptFactoryFactory.create(notes, fileName, basePatchSet.id(), pId, prefs, currentUser.get());
    } else if (parentNum > 0) {
        psf = patchScriptFactoryFactory.create(notes, fileName, parentNum, pId, prefs, currentUser.get());
    } else {
        psf = patchScriptFactoryFactory.create(notes, fileName, null, pId, prefs, currentUser.get());
    }
    try {
        PatchScript ps = psf.call();
        Project.NameKey projectName = resource.getRevision().getChange().getProject();
        ProjectState state = projectCache.get(projectName).orElseThrow(illegalState(projectName));
        DiffSide sideA = DiffSide.create(ps.getFileInfoA(), MoreObjects.firstNonNull(ps.getOldName(), ps.getNewName()), DiffSide.Type.SIDE_A);
        DiffSide sideB = DiffSide.create(ps.getFileInfoB(), ps.getNewName(), DiffSide.Type.SIDE_B);
        DiffWebLinksProvider webLinksProvider = new DiffWebLinksProviderImpl(sideA, sideB, projectName, basePatchSet, webLinks, resource);
        DiffInfoCreator diffInfoCreator = new DiffInfoCreator(state, webLinksProvider, intraline);
        DiffInfo result = diffInfoCreator.create(ps, sideA, sideB);
        Response<DiffInfo> r = Response.ok(result);
        if (resource.isCacheable()) {
            r.caching(CacheControl.PRIVATE(7, TimeUnit.DAYS));
        }
        return r;
    } catch (NoSuchChangeException e) {
        throw new ResourceNotFoundException(e.getMessage(), e);
    } catch (LargeObjectException e) {
        throw new ResourceConflictException(e.getMessage(), e);
    }
}
Also used : PatchScript(com.google.gerrit.common.data.PatchScript) PatchSet(com.google.gerrit.entities.PatchSet) RevisionResource(com.google.gerrit.server.change.RevisionResource) IdString(com.google.gerrit.extensions.restapi.IdString) ChangeNotes(com.google.gerrit.server.notedb.ChangeNotes) DiffSide(com.google.gerrit.server.diff.DiffSide) Project(com.google.gerrit.entities.Project) LargeObjectException(com.google.gerrit.server.git.LargeObjectException) ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) NoSuchChangeException(com.google.gerrit.server.project.NoSuchChangeException) PatchScriptFactory(com.google.gerrit.server.patch.PatchScriptFactory) DiffWebLinksProvider(com.google.gerrit.server.diff.DiffWebLinksProvider) DiffInfoCreator(com.google.gerrit.server.diff.DiffInfoCreator) BadRequestException(com.google.gerrit.extensions.restapi.BadRequestException) ProjectState(com.google.gerrit.server.project.ProjectState) ResourceNotFoundException(com.google.gerrit.extensions.restapi.ResourceNotFoundException) DiffPreferencesInfo(com.google.gerrit.extensions.client.DiffPreferencesInfo) DiffInfo(com.google.gerrit.extensions.common.DiffInfo)

Example 40 with ProjectState

use of com.google.gerrit.server.project.ProjectState in project gerrit by GerritCodeReview.

the class SubmitStrategyOp method postUpdate.

@Override
public final void postUpdate(Context ctx) throws Exception {
    postUpdateImpl(ctx);
    if (command != null) {
        args.tagCache.updateFastForward(getProject(), command.getRefName(), command.getOldId(), command.getNewId());
        // per project even if multiple changes to refs/meta/config are submitted.
        if (RefNames.REFS_CONFIG.equals(getDest().get())) {
            args.projectCache.evict(getProject());
            ProjectState p = args.projectCache.get(getProject());
            try (Repository git = args.repoManager.openRepository(getProject())) {
                git.setGitwebDescription(p.getProject().getDescription());
            } catch (IOException e) {
                log.error("cannot update description of " + p.getProject().getName(), e);
            }
        }
    }
    // have failed fast in one of the other steps.
    try {
        args.mergedSenderFactory.create(ctx.getProject(), getId(), submitter.getAccountId(), args.notifyHandling, args.accountsToNotify).sendAsync();
    } catch (Exception e) {
        log.error("Cannot email merged notification for " + getId(), e);
    }
    if (mergeResultRev != null && !args.dryrun) {
        args.changeMerged.fire(updatedChange, mergedPatchSet, args.accountCache.get(submitter.getAccountId()).getAccount(), args.mergeTip.getCurrentTip().name(), ctx.getWhen());
    }
}
Also used : Repository(org.eclipse.jgit.lib.Repository) ProjectState(com.google.gerrit.server.project.ProjectState) IOException(java.io.IOException) SubmoduleException(com.google.gerrit.server.git.SubmoduleException) OrmException(com.google.gwtorm.server.OrmException) MissingObjectException(org.eclipse.jgit.errors.MissingObjectException) IncorrectObjectTypeException(org.eclipse.jgit.errors.IncorrectObjectTypeException) IntegrationException(com.google.gerrit.server.git.IntegrationException) IOException(java.io.IOException)

Aggregations

ProjectState (com.google.gerrit.server.project.ProjectState)86 Project (com.google.gerrit.entities.Project)20 ResourceConflictException (com.google.gerrit.extensions.restapi.ResourceConflictException)19 IOException (java.io.IOException)18 Repository (org.eclipse.jgit.lib.Repository)18 AuthException (com.google.gerrit.extensions.restapi.AuthException)16 ResourceNotFoundException (com.google.gerrit.extensions.restapi.ResourceNotFoundException)14 PermissionBackendException (com.google.gerrit.server.permissions.PermissionBackendException)14 AbstractDaemonTest (com.google.gerrit.acceptance.AbstractDaemonTest)13 Change (com.google.gerrit.entities.Change)13 ObjectId (org.eclipse.jgit.lib.ObjectId)13 Test (org.junit.Test)13 BadRequestException (com.google.gerrit.extensions.restapi.BadRequestException)12 ChangeData (com.google.gerrit.server.query.change.ChangeData)11 Inject (com.google.inject.Inject)10 ConfigInvalidException (org.eclipse.jgit.errors.ConfigInvalidException)10 RepositoryNotFoundException (org.eclipse.jgit.errors.RepositoryNotFoundException)10 StorageException (com.google.gerrit.exceptions.StorageException)9 ProjectInfo (com.google.gerrit.extensions.common.ProjectInfo)9 ProjectResource (com.google.gerrit.server.project.ProjectResource)9