Search in sources :

Example 66 with ReceiveCommand

use of org.eclipse.jgit.transport.ReceiveCommand in project gitblit by gitblit.

the class PatchsetReceivePack method processPatchset.

/**
 * Creates or updates an ticket with the specified patchset.
 *
 * @param cmd
 * @return a ticket if the creation or update was successful
 */
private TicketModel processPatchset(PatchsetCommand cmd) {
    Change change = cmd.getChange();
    if (cmd.isNewTicket()) {
        // create the ticket object
        TicketModel ticket = ticketService.createTicket(repository, cmd.getTicketId(), change);
        if (ticket != null) {
            sendInfo("");
            sendHeader("#{0,number,0}: {1}", ticket.number, StringUtils.trimString(ticket.title, Constants.LEN_SHORTLOG));
            sendInfo("created proposal ticket from patchset");
            sendInfo(ticketService.getTicketUrl(ticket));
            sendInfo("");
            // log the new patch ref
            RefLogUtils.updateRefLog(user, getRepository(), Arrays.asList(new ReceiveCommand(cmd.getOldId(), cmd.getNewId(), cmd.getRefName())));
            // call any patchset hooks
            for (PatchsetHook hook : gitblit.getExtensions(PatchsetHook.class)) {
                try {
                    hook.onNewPatchset(ticket);
                } catch (Exception e) {
                    LOGGER.error("Failed to execute extension", e);
                }
            }
            return ticket;
        } else {
            sendError("FAILED to create ticket");
        }
    } else {
        // update an existing ticket
        TicketModel ticket = ticketService.updateTicket(repository, cmd.getTicketId(), change);
        if (ticket != null) {
            sendInfo("");
            sendHeader("#{0,number,0}: {1}", ticket.number, StringUtils.trimString(ticket.title, Constants.LEN_SHORTLOG));
            if (change.patchset.rev == 1) {
                // new patchset
                sendInfo("uploaded patchset {0} ({1})", change.patchset.number, change.patchset.type.toString());
            } else {
                // updated patchset
                sendInfo("added {0} {1} to patchset {2}", change.patchset.added, change.patchset.added == 1 ? "commit" : "commits", change.patchset.number);
            }
            sendInfo(ticketService.getTicketUrl(ticket));
            sendInfo("");
            // log the new patchset ref
            RefLogUtils.updateRefLog(user, getRepository(), Arrays.asList(new ReceiveCommand(cmd.getOldId(), cmd.getNewId(), cmd.getRefName())));
            // call any patchset hooks
            final boolean isNewPatchset = change.patchset.rev == 1;
            for (PatchsetHook hook : gitblit.getExtensions(PatchsetHook.class)) {
                try {
                    if (isNewPatchset) {
                        hook.onNewPatchset(ticket);
                    } else {
                        hook.onUpdatePatchset(ticket);
                    }
                } catch (Exception e) {
                    LOGGER.error("Failed to execute extension", e);
                }
            }
            // return the updated ticket
            return ticket;
        } else {
            sendError("FAILED to upload {0} for ticket {1,number,0}", change.patchset, cmd.getTicketId());
        }
    }
    return null;
}
Also used : ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) PatchsetHook(com.gitblit.extensions.PatchsetHook) TicketModel(com.gitblit.models.TicketModel) Change(com.gitblit.models.TicketModel.Change) IOException(java.io.IOException)

Example 67 with ReceiveCommand

use of org.eclipse.jgit.transport.ReceiveCommand in project gitblit by gitblit.

the class PatchsetReceivePack method executeCommands.

/**
 * Execute commands to update references.
 */
@Override
protected void executeCommands() {
    // we process patchsets unless the user is pushing something special
    boolean processPatchsets = true;
    for (ReceiveCommand cmd : filterCommands(Result.NOT_ATTEMPTED)) {
        if (ticketService instanceof BranchTicketService && BranchTicketService.BRANCH.equals(cmd.getRefName())) {
            // the user is pushing an update to the BranchTicketService data
            processPatchsets = false;
        }
    }
    // reset the patchset refs to NOT_ATTEMPTED (see validateCommands)
    for (ReceiveCommand cmd : filterCommands(Result.OK)) {
        if (isPatchsetRef(cmd.getRefName())) {
            cmd.setResult(Result.NOT_ATTEMPTED);
        } else if (ticketService instanceof BranchTicketService && BranchTicketService.BRANCH.equals(cmd.getRefName())) {
            // the user is pushing an update to the BranchTicketService data
            processPatchsets = false;
        }
    }
    List<ReceiveCommand> toApply = filterCommands(Result.NOT_ATTEMPTED);
    if (toApply.isEmpty()) {
        return;
    }
    ProgressMonitor updating = NullProgressMonitor.INSTANCE;
    boolean sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K);
    if (sideBand) {
        SideBandProgressMonitor pm = new SideBandProgressMonitor(msgOut);
        pm.setDelayStart(250, TimeUnit.MILLISECONDS);
        updating = pm;
    }
    BatchRefUpdate batch = getRepository().getRefDatabase().newBatchUpdate();
    batch.setAllowNonFastForwards(isAllowNonFastForwards());
    batch.setRefLogIdent(getRefLogIdent());
    batch.setRefLogMessage("push", true);
    ReceiveCommand patchsetRefCmd = null;
    PatchsetCommand patchsetCmd = null;
    for (ReceiveCommand cmd : toApply) {
        if (Result.NOT_ATTEMPTED != cmd.getResult()) {
            // Already rejected by the core receive process.
            continue;
        }
        if (isPatchsetRef(cmd.getRefName()) && processPatchsets) {
            if (ticketService == null) {
                sendRejection(cmd, "Sorry, the ticket service is unavailable and can not accept patchsets at this time.");
                continue;
            }
            if (!ticketService.isReady()) {
                sendRejection(cmd, "Sorry, the ticket service can not accept patchsets at this time.");
                continue;
            }
            if (UserModel.ANONYMOUS.equals(user)) {
                // server allows anonymous pushes, but anonymous patchset
                // contributions are prohibited by design
                sendRejection(cmd, "Sorry, anonymous patchset contributions are prohibited.");
                continue;
            }
            final Matcher m = NEW_PATCHSET.matcher(cmd.getRefName());
            if (m.matches()) {
                // prohibit pushing directly to a patchset ref
                long id = getTicketId(cmd.getRefName());
                sendError("You may not directly push directly to a patchset ref!");
                sendError("Instead, please push to one the following:");
                sendError(" - {0}{1,number,0}", Constants.R_FOR, id);
                sendError(" - {0}{1,number,0}", Constants.R_TICKET, id);
                sendRejection(cmd, "protected ref");
                continue;
            }
            if (hasRefNamespace(Constants.R_FOR)) {
                // the refs/for/ namespace exists and it must not
                LOGGER.error("{} already has refs in the {} namespace", repository.name, Constants.R_FOR);
                sendRejection(cmd, "Sorry, a repository administrator will have to remove the {} namespace", Constants.R_FOR);
                continue;
            }
            if (cmd.getNewId().equals(ObjectId.zeroId())) {
                // ref deletion request
                if (cmd.getRefName().startsWith(Constants.R_TICKET)) {
                    if (user.canDeleteRef(repository)) {
                        batch.addCommand(cmd);
                    } else {
                        sendRejection(cmd, "Sorry, you do not have permission to delete {}", cmd.getRefName());
                    }
                } else {
                    sendRejection(cmd, "Sorry, you can not delete {}", cmd.getRefName());
                }
                continue;
            }
            if (patchsetRefCmd != null) {
                sendRejection(cmd, "You may only push one patchset at a time.");
                continue;
            }
            LOGGER.info(MessageFormat.format("Verifying {0} push ref \"{1}\" received from {2}", repository.name, cmd.getRefName(), user.username));
            // responsible verification
            String responsible = PatchsetCommand.getSingleOption(cmd, PatchsetCommand.RESPONSIBLE);
            if (!StringUtils.isEmpty(responsible)) {
                UserModel assignee = gitblit.getUserModel(responsible);
                if (assignee == null) {
                    // no account by this name
                    sendRejection(cmd, "{0} can not be assigned any tickets because there is no user account by that name", responsible);
                    continue;
                } else if (!assignee.canPush(repository)) {
                    // account does not have RW permissions
                    sendRejection(cmd, "{0} ({1}) can not be assigned any tickets because the user does not have RW permissions for {2}", assignee.getDisplayName(), assignee.username, repository.name);
                    continue;
                }
            }
            // milestone verification
            String milestone = PatchsetCommand.getSingleOption(cmd, PatchsetCommand.MILESTONE);
            if (!StringUtils.isEmpty(milestone)) {
                TicketMilestone milestoneModel = ticketService.getMilestone(repository, milestone);
                if (milestoneModel == null) {
                    // milestone does not exist
                    sendRejection(cmd, "Sorry, \"{0}\" is not a valid milestone!", milestone);
                    continue;
                }
            }
            // watcher verification
            List<String> watchers = PatchsetCommand.getOptions(cmd, PatchsetCommand.WATCH);
            if (!ArrayUtils.isEmpty(watchers)) {
                boolean verified = true;
                for (String watcher : watchers) {
                    UserModel user = gitblit.getUserModel(watcher);
                    if (user == null) {
                        // watcher does not exist
                        sendRejection(cmd, "Sorry, \"{0}\" is not a valid username for the watch list!", watcher);
                        verified = false;
                        break;
                    }
                }
                if (!verified) {
                    continue;
                }
            }
            patchsetRefCmd = cmd;
            patchsetCmd = preparePatchset(cmd);
            if (patchsetCmd != null) {
                batch.addCommand(patchsetCmd);
            }
            continue;
        }
        batch.addCommand(cmd);
    }
    if (!batch.getCommands().isEmpty()) {
        try {
            batch.execute(getRevWalk(), updating);
        } catch (IOException err) {
            for (ReceiveCommand cmd : toApply) {
                if (cmd.getResult() == Result.NOT_ATTEMPTED) {
                    sendRejection(cmd, "lock error: {0}", err.getMessage());
                    LOGGER.error(MessageFormat.format("failed to lock {0}:{1}", repository.name, cmd.getRefName()), err);
                }
            }
        }
    }
    // 
    if (patchsetRefCmd != null && patchsetCmd != null) {
        if (!patchsetCmd.getResult().equals(Result.OK)) {
            // patchset command failed!
            LOGGER.error(patchsetCmd.getType() + " " + patchsetCmd.getRefName() + " " + patchsetCmd.getResult());
            patchsetRefCmd.setResult(patchsetCmd.getResult(), patchsetCmd.getMessage());
        } else {
            // all patchset commands were applied
            patchsetRefCmd.setResult(Result.OK);
            // update the ticket branch ref
            RefUpdate ru = updateRef(patchsetCmd.getTicketBranch(), patchsetCmd.getNewId(), patchsetCmd.getPatchsetType());
            updateReflog(ru);
            TicketModel ticket = processPatchset(patchsetCmd);
            if (ticket != null) {
                ticketNotifier.queueMailing(ticket);
            }
        }
    }
    // 
    // if there are standard ref update receive commands that were
    // successfully processed, process referenced tickets, if any
    // 
    List<ReceiveCommand> allUpdates = ReceiveCommand.filter(batch.getCommands(), Result.OK);
    List<ReceiveCommand> refUpdates = excludePatchsetCommands(allUpdates);
    List<ReceiveCommand> stdUpdates = excludeTicketCommands(refUpdates);
    if (!stdUpdates.isEmpty()) {
        int ticketsProcessed = 0;
        for (ReceiveCommand cmd : stdUpdates) {
            switch(cmd.getType()) {
                case CREATE:
                case UPDATE:
                    if (cmd.getRefName().startsWith(Constants.R_HEADS)) {
                        Collection<TicketModel> tickets = processReferencedTickets(cmd);
                        ticketsProcessed += tickets.size();
                        for (TicketModel ticket : tickets) {
                            ticketNotifier.queueMailing(ticket);
                        }
                    }
                    break;
                case UPDATE_NONFASTFORWARD:
                    if (cmd.getRefName().startsWith(Constants.R_HEADS)) {
                        String base = JGitUtils.getMergeBase(getRepository(), cmd.getOldId(), cmd.getNewId());
                        List<TicketLink> deletedRefs = JGitUtils.identifyTicketsBetweenCommits(getRepository(), settings, base, cmd.getOldId().name());
                        for (TicketLink link : deletedRefs) {
                            link.isDelete = true;
                        }
                        Change deletion = new Change(user.username);
                        deletion.pendingLinks = deletedRefs;
                        ticketService.updateTicket(repository, 0, deletion);
                        Collection<TicketModel> tickets = processReferencedTickets(cmd);
                        ticketsProcessed += tickets.size();
                        for (TicketModel ticket : tickets) {
                            ticketNotifier.queueMailing(ticket);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        if (ticketsProcessed == 1) {
            sendInfo("1 ticket updated");
        } else if (ticketsProcessed > 1) {
            sendInfo("{0} tickets updated", ticketsProcessed);
        }
    }
    // reset the ticket caches for the repository
    ticketService.resetCaches(repository);
}
Also used : ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) BranchTicketService(com.gitblit.tickets.BranchTicketService) Matcher(java.util.regex.Matcher) TicketModel(com.gitblit.models.TicketModel) IOException(java.io.IOException) Change(com.gitblit.models.TicketModel.Change) NullProgressMonitor(org.eclipse.jgit.lib.NullProgressMonitor) ProgressMonitor(org.eclipse.jgit.lib.ProgressMonitor) UserModel(com.gitblit.models.UserModel) TicketLink(com.gitblit.models.TicketModel.TicketLink) BatchRefUpdate(org.eclipse.jgit.lib.BatchRefUpdate) TicketMilestone(com.gitblit.tickets.TicketMilestone) RefUpdate(org.eclipse.jgit.lib.RefUpdate) BatchRefUpdate(org.eclipse.jgit.lib.BatchRefUpdate)

Example 68 with ReceiveCommand

use of org.eclipse.jgit.transport.ReceiveCommand in project gitblit by gitblit.

the class PatchsetReceivePack method updateReflog.

private void updateReflog(RefUpdate ru) {
    if (ru == null) {
        return;
    }
    ReceiveCommand.Type type = null;
    switch(ru.getResult()) {
        case NEW:
            type = Type.CREATE;
            break;
        case FAST_FORWARD:
            type = Type.UPDATE;
            break;
        case FORCED:
            type = Type.UPDATE_NONFASTFORWARD;
            break;
        default:
            LOGGER.error(MessageFormat.format("unexpected ref update type {0} for {1}", ru.getResult(), ru.getName()));
            return;
    }
    ReceiveCommand cmd = new ReceiveCommand(ru.getOldObjectId(), ru.getNewObjectId(), ru.getName(), type);
    RefLogUtils.updateRefLog(user, getRepository(), Arrays.asList(cmd));
}
Also used : ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) Type(org.eclipse.jgit.transport.ReceiveCommand.Type)

Example 69 with ReceiveCommand

use of org.eclipse.jgit.transport.ReceiveCommand in project gitblit by gitblit.

the class BranchTicketService method onRefsChanged.

/**
 * Listen for tickets branch changes and (re)index tickets, as appropriate
 */
@Override
public synchronized void onRefsChanged(RefsChangedEvent event) {
    if (!(event instanceof ReceiveCommandEvent)) {
        return;
    }
    ReceiveCommandEvent branchUpdate = (ReceiveCommandEvent) event;
    RepositoryModel repository = branchUpdate.model;
    ReceiveCommand cmd = branchUpdate.cmd;
    try {
        switch(cmd.getType()) {
            case CREATE:
            case UPDATE_NONFASTFORWARD:
                // reindex everything
                reindex(repository);
                break;
            case UPDATE:
                // incrementally index ticket updates
                resetCaches(repository);
                long start = System.nanoTime();
                log.info("incrementally indexing {} ticket branch due to received ref update", repository.name);
                Repository db = repositoryManager.getRepository(repository.name);
                try {
                    Set<Long> ids = new HashSet<Long>();
                    List<PathChangeModel> paths = JGitUtils.getFilesInRange(db, cmd.getOldId().getName(), cmd.getNewId().getName());
                    for (PathChangeModel path : paths) {
                        String name = path.name.substring(path.name.lastIndexOf('/') + 1);
                        if (!JOURNAL.equals(name)) {
                            continue;
                        }
                        String tid = path.path.split("/")[2];
                        long ticketId = Long.parseLong(tid);
                        if (!ids.contains(ticketId)) {
                            ids.add(ticketId);
                            TicketModel ticket = getTicket(repository, ticketId);
                            log.info(MessageFormat.format("indexing ticket #{0,number,0}: {1}", ticketId, ticket.title));
                            indexer.index(ticket);
                        }
                    }
                    long end = System.nanoTime();
                    log.info("incremental indexing of {0} ticket(s) completed in {1} msecs", ids.size(), TimeUnit.NANOSECONDS.toMillis(end - start));
                } finally {
                    db.close();
                }
                break;
            default:
                log.warn("Unexpected receive type {} in BranchTicketService.onRefsChanged" + cmd.getType());
                break;
        }
    } catch (Exception e) {
        log.error("failed to reindex " + repository.name, e);
    }
}
Also used : ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) PathChangeModel(com.gitblit.models.PathModel.PathChangeModel) TicketModel(com.gitblit.models.TicketModel) RepositoryModel(com.gitblit.models.RepositoryModel) ConcurrentRefUpdateException(org.eclipse.jgit.api.errors.ConcurrentRefUpdateException) IOException(java.io.IOException) Repository(org.eclipse.jgit.lib.Repository) ReceiveCommandEvent(com.gitblit.git.ReceiveCommandEvent) AtomicLong(java.util.concurrent.atomic.AtomicLong) HashSet(java.util.HashSet)

Example 70 with ReceiveCommand

use of org.eclipse.jgit.transport.ReceiveCommand in project gitblit by gitblit.

the class RefLogUtils method createIndex.

/**
 * Creates an in-memory index of the reflog entry.
 *
 * @param repo
 * @param headId
 * @param commands
 * @return an in-memory index
 * @throws IOException
 */
private static DirCache createIndex(Repository repo, ObjectId headId, Collection<ReceiveCommand> commands) throws IOException {
    DirCache inCoreIndex = DirCache.newInCore();
    DirCacheBuilder dcBuilder = inCoreIndex.builder();
    ObjectInserter inserter = repo.newObjectInserter();
    long now = System.currentTimeMillis();
    Set<String> ignorePaths = new TreeSet<String>();
    try {
        // add receive commands to the temporary index
        for (ReceiveCommand command : commands) {
            // use the ref names as the path names
            String path = command.getRefName();
            ignorePaths.add(path);
            StringBuilder change = new StringBuilder();
            change.append(command.getType().name()).append(' ');
            switch(command.getType()) {
                case CREATE:
                    change.append(ObjectId.zeroId().getName());
                    change.append(' ');
                    change.append(command.getNewId().getName());
                    break;
                case UPDATE:
                case UPDATE_NONFASTFORWARD:
                    change.append(command.getOldId().getName());
                    change.append(' ');
                    change.append(command.getNewId().getName());
                    break;
                case DELETE:
                    change = null;
                    break;
            }
            if (change == null) {
                // ref deleted
                continue;
            }
            String content = change.toString();
            // create an index entry for this attachment
            final DirCacheEntry dcEntry = new DirCacheEntry(path);
            dcEntry.setLength(content.length());
            dcEntry.setLastModified(now);
            dcEntry.setFileMode(FileMode.REGULAR_FILE);
            // insert object
            dcEntry.setObjectId(inserter.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, content.getBytes("UTF-8")));
            // add to temporary in-core index
            dcBuilder.add(dcEntry);
        }
        // Traverse HEAD to add all other paths
        TreeWalk treeWalk = new TreeWalk(repo);
        int hIdx = -1;
        if (headId != null)
            hIdx = treeWalk.addTree(new RevWalk(repo).parseTree(headId));
        treeWalk.setRecursive(true);
        while (treeWalk.next()) {
            String path = treeWalk.getPathString();
            CanonicalTreeParser hTree = null;
            if (hIdx != -1)
                hTree = treeWalk.getTree(hIdx, CanonicalTreeParser.class);
            if (!ignorePaths.contains(path)) {
                // add entries from HEAD for all other paths
                if (hTree != null) {
                    // create a new DirCacheEntry with data retrieved from
                    // HEAD
                    final DirCacheEntry dcEntry = new DirCacheEntry(path);
                    dcEntry.setObjectId(hTree.getEntryObjectId());
                    dcEntry.setFileMode(hTree.getEntryFileMode());
                    // add to temporary in-core index
                    dcBuilder.add(dcEntry);
                }
            }
        }
        // release the treewalk
        treeWalk.close();
        // finish temporary in-core index used for this commit
        dcBuilder.finish();
    } finally {
        inserter.close();
    }
    return inCoreIndex;
}
Also used : ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) DirCacheBuilder(org.eclipse.jgit.dircache.DirCacheBuilder) DirCacheEntry(org.eclipse.jgit.dircache.DirCacheEntry) RevWalk(org.eclipse.jgit.revwalk.RevWalk) CanonicalTreeParser(org.eclipse.jgit.treewalk.CanonicalTreeParser) DirCache(org.eclipse.jgit.dircache.DirCache) ObjectInserter(org.eclipse.jgit.lib.ObjectInserter) TreeSet(java.util.TreeSet) TreeWalk(org.eclipse.jgit.treewalk.TreeWalk)

Aggregations

ReceiveCommand (org.eclipse.jgit.transport.ReceiveCommand)82 IOException (java.io.IOException)29 ArrayList (java.util.ArrayList)23 ObjectId (org.eclipse.jgit.lib.ObjectId)23 BatchRefUpdate (org.eclipse.jgit.lib.BatchRefUpdate)22 RevWalk (org.eclipse.jgit.revwalk.RevWalk)21 Repository (org.eclipse.jgit.lib.Repository)19 Ref (org.eclipse.jgit.lib.Ref)18 Test (org.junit.Test)16 RepositoryModel (com.gitblit.models.RepositoryModel)13 Map (java.util.Map)13 ResourceConflictException (com.google.gerrit.extensions.restapi.ResourceConflictException)11 RestApiException (com.google.gerrit.extensions.restapi.RestApiException)10 StorageException (com.google.gerrit.exceptions.StorageException)9 ObjectInserter (org.eclipse.jgit.lib.ObjectInserter)9 PersonIdent (org.eclipse.jgit.lib.PersonIdent)9 RevCommit (org.eclipse.jgit.revwalk.RevCommit)9 AuthException (com.google.gerrit.extensions.restapi.AuthException)8 PermissionBackendException (com.google.gerrit.server.permissions.PermissionBackendException)8 Collection (java.util.Collection)8