Example #1
0
 @Override
 public String apply(ProjectResource rsrc)
     throws AuthException, ResourceNotFoundException, IOException {
   try (Repository repo = repoManager.openRepository(rsrc.getNameKey())) {
     Ref head = repo.getRefDatabase().exactRef(Constants.HEAD);
     if (head == null) {
       throw new ResourceNotFoundException(Constants.HEAD);
     } else if (head.isSymbolic()) {
       String n = head.getTarget().getName();
       if (rsrc.getControl().controlForRef(n).isVisible()) {
         return n;
       }
       throw new AuthException("not allowed to see HEAD");
     } else if (head.getObjectId() != null) {
       try (RevWalk rw = new RevWalk(repo)) {
         RevCommit commit = rw.parseCommit(head.getObjectId());
         if (rsrc.getControl().canReadCommit(db.get(), repo, commit)) {
           return head.getObjectId().name();
         }
         throw new AuthException("not allowed to see HEAD");
       } catch (MissingObjectException | IncorrectObjectTypeException e) {
         if (rsrc.getControl().isOwner()) {
           return head.getObjectId().name();
         }
         throw new AuthException("not allowed to see HEAD");
       }
     }
     throw new ResourceNotFoundException(Constants.HEAD);
   } catch (RepositoryNotFoundException e) {
     throw new ResourceNotFoundException(rsrc.getName());
   }
 }
 /**
  * Returns a list of references in the repository matching "refs". If the repository is null or
  * empty, an empty list is returned.
  *
  * @param repository
  * @param refs if unspecified, all refs are returned
  * @param fullName if true, /refs/something/yadayadayada is returned. If false, yadayadayada is
  *     returned.
  * @param maxCount if < 0, all references are returned
  * @return list of references
  */
 private static List<RefModel> getRefs(
     Repository repository, String refs, boolean fullName, int maxCount) {
   List<RefModel> list = new ArrayList<RefModel>();
   if (maxCount == 0) {
     return list;
   }
   if (!hasCommits(repository)) {
     return list;
   }
   try {
     Map<String, Ref> map = repository.getRefDatabase().getRefs(refs);
     RevWalk rw = new RevWalk(repository);
     for (Entry<String, Ref> entry : map.entrySet()) {
       Ref ref = entry.getValue();
       RevObject object = rw.parseAny(ref.getObjectId());
       String name = entry.getKey();
       if (fullName && !(refs == null)) {
         name = refs + name;
       }
       list.add(new RefModel(name, ref, object));
     }
     rw.dispose();
     Collections.sort(list);
     Collections.reverse(list);
     if (maxCount > 0 && list.size() > maxCount) {
       list = new ArrayList<RefModel>(list.subList(0, maxCount));
     }
   } catch (IOException e) {
     // todo
     Logger.error(e, e.getMessage());
   }
   return list;
 }
  private Iterable<ChangeData> byCommitsOnBranchNotMergedFromDatabase(
      Repository repo, ReviewDb db, Branch.NameKey branch, List<String> hashes)
      throws OrmException, IOException {
    Set<Change.Id> changeIds = Sets.newHashSetWithExpectedSize(hashes.size());
    String lastPrefix = null;
    for (Ref ref : repo.getRefDatabase().getRefs(RefNames.REFS_CHANGES).values()) {
      String r = ref.getName();
      if ((lastPrefix != null && r.startsWith(lastPrefix))
          || !hashes.contains(ref.getObjectId().name())) {
        continue;
      }
      Change.Id id = Change.Id.fromRef(r);
      if (id == null) {
        continue;
      }
      if (changeIds.add(id)) {
        lastPrefix = r.substring(0, r.lastIndexOf('/'));
      }
    }

    List<ChangeData> cds = new ArrayList<>(hashes.size());
    for (Change c : db.changes().get(changeIds)) {
      if (c.getDest().equals(branch) && c.getStatus() != Change.Status.MERGED) {
        cds.add(changeDataFactory.create(db, c));
      }
    }
    return cds;
  }
 private boolean isContainedInAnyRemoteBranch(RevCommit commit) {
   try {
     Collection<Ref> refs = repository.getRefDatabase().getRefs(Constants.R_REMOTES).values();
     return RevUtils.isContainedInAnyRef(repository, commit, refs);
   } catch (IOException e) {
     // The result only affects a warning, so pretend there was no
     // problem.
     return false;
   }
 }
Example #5
0
 private List<Ref> getBranches() {
   List<Ref> ref = new ArrayList<Ref>();
   try {
     ref.addAll(db.getRefDatabase().getRefs(Constants.R_HEADS).values());
     ref.addAll(db.getRefDatabase().getRefs(Constants.R_REMOTES).values());
   } catch (IOException e) {
     Activator.logError(e.getMessage(), e);
   }
   return ref;
 }
Example #6
0
  private Set<RevCommit> getAlreadyAccepted(CodeReviewCommit branchTip)
      throws IntegrationException {
    Set<RevCommit> alreadyAccepted = new HashSet<>();

    if (branchTip != null) {
      alreadyAccepted.add(branchTip);
    }

    try {
      for (Ref r : repo.getRefDatabase().getRefs(Constants.R_HEADS).values()) {
        try {
          alreadyAccepted.add(rw.parseCommit(r.getObjectId()));
        } catch (IncorrectObjectTypeException iote) {
          // Not a commit? Skip over it.
        }
      }
    } catch (IOException e) {
      throw new IntegrationException("Failed to determine already accepted commits.", e);
    }

    logDebug("Found {} existing heads", alreadyAccepted.size());
    return alreadyAccepted;
  }
Example #7
0
  private void fillBranches() {
    Repository repository = getCommit().getRepository();
    RevCommit commit = getCommit().getRevCommit();
    RevWalk revWalk = new RevWalk(repository);
    List<Ref> result = new ArrayList<Ref>();
    try {
      Map<String, Ref> refsMap = new HashMap<String, Ref>();
      refsMap.putAll(repository.getRefDatabase().getRefs(Constants.R_HEADS));
      refsMap.putAll(repository.getRefDatabase().getRefs(Constants.R_REMOTES));
      for (Ref ref : refsMap.values()) {
        if (ref.isSymbolic()) continue;
        RevCommit headCommit = revWalk.parseCommit(ref.getObjectId());
        RevCommit base = revWalk.parseCommit(commit);
        if (revWalk.isMergedInto(base, headCommit)) result.add(ref);
      }
    } catch (IOException ignored) {
      // Ignored
    }

    branchViewer.setInput(result);
    branchSection.setText(
        MessageFormat.format(
            UIText.CommitEditorPage_SectionBranches, Integer.valueOf(result.size())));
  }
Example #8
0
  /**
   * Update the submodules in one branch of one repository.
   *
   * @param subscriber the branch of the repository which should be changed.
   * @param updates submodule updates which should be updated to.
   * @throws SubmoduleException
   */
  private void updateGitlinks(
      ReviewDb db, Branch.NameKey subscriber, Collection<SubmoduleSubscription> updates)
      throws SubmoduleException {
    PersonIdent author = null;

    Repository pdb = null;
    RevWalk recRw = null;

    StringBuilder msgbuf = new StringBuilder("Updated git submodules\n\n");
    try {
      boolean sameAuthorForAll = true;

      pdb = repoManager.openRepository(subscriber.getParentKey());
      if (pdb.getRef(subscriber.get()) == null) {
        throw new SubmoduleException(
            "The branch was probably deleted from the subscriber repository");
      }

      DirCache dc = readTree(pdb, pdb.getRef(subscriber.get()));
      DirCacheEditor ed = dc.editor();

      for (SubmoduleSubscription s : updates) {
        try (Repository subrepo = repoManager.openRepository(s.getSubmodule().getParentKey());
            RevWalk rw = CodeReviewCommit.newRevWalk(subrepo)) {
          Ref ref = subrepo.getRefDatabase().exactRef(s.getSubmodule().get());
          if (ref == null) {
            ed.add(new DeletePath(s.getPath()));
            continue;
          }

          final ObjectId updateTo = ref.getObjectId();
          RevCommit newCommit = rw.parseCommit(updateTo);

          if (author == null) {
            author = newCommit.getAuthorIdent();
          } else if (!author.equals(newCommit.getAuthorIdent())) {
            sameAuthorForAll = false;
          }

          DirCacheEntry dce = dc.getEntry(s.getPath());
          ObjectId oldId = null;
          if (dce != null) {
            if (!dce.getFileMode().equals(FileMode.GITLINK)) {
              log.error(
                  "Requested to update gitlink "
                      + s.getPath()
                      + " in "
                      + s.getSubmodule().getParentKey().get()
                      + " but entry "
                      + "doesn't have gitlink file mode.");
              continue;
            }
            oldId = dce.getObjectId();
          } else {
            // This submodule did not exist before. We do not want to add
            // the full submodule history to the commit message, so omit it.
            oldId = updateTo;
          }

          ed.add(
              new PathEdit(s.getPath()) {
                @Override
                public void apply(DirCacheEntry ent) {
                  ent.setFileMode(FileMode.GITLINK);
                  ent.setObjectId(updateTo);
                }
              });
          if (verboseSuperProject) {
            msgbuf.append("Project: " + s.getSubmodule().getParentKey().get());
            msgbuf.append(" " + s.getSubmodule().getShortName());
            msgbuf.append(" " + updateTo.getName());
            msgbuf.append("\n\n");

            try {
              rw.markStart(newCommit);

              if (oldId != null) {
                rw.markUninteresting(rw.parseCommit(oldId));
              }
              for (RevCommit c : rw) {
                msgbuf.append(c.getFullMessage() + "\n\n");
              }
            } catch (IOException e) {
              logAndThrowSubmoduleException(
                  "Could not perform a revwalk to " + "create superproject commit message", e);
            }
          }
        }
      }
      ed.finish();

      if (!sameAuthorForAll || author == null) {
        author = myIdent;
      }

      ObjectInserter oi = pdb.newObjectInserter();
      ObjectId tree = dc.writeTree(oi);

      ObjectId currentCommitId = pdb.getRef(subscriber.get()).getObjectId();

      CommitBuilder commit = new CommitBuilder();
      commit.setTreeId(tree);
      commit.setParentIds(new ObjectId[] {currentCommitId});
      commit.setAuthor(author);
      commit.setCommitter(myIdent);
      commit.setMessage(msgbuf.toString());
      oi.insert(commit);
      oi.flush();

      ObjectId commitId = oi.idFor(Constants.OBJ_COMMIT, commit.build());

      final RefUpdate rfu = pdb.updateRef(subscriber.get());
      rfu.setForceUpdate(false);
      rfu.setNewObjectId(commitId);
      rfu.setExpectedOldObjectId(currentCommitId);
      rfu.setRefLogMessage("Submit to " + subscriber.getParentKey().get(), true);

      switch (rfu.update()) {
        case NEW:
        case FAST_FORWARD:
          gitRefUpdated.fire(subscriber.getParentKey(), rfu);
          changeHooks.doRefUpdatedHook(subscriber, rfu, account);
          // TODO since this is performed "in the background" no mail will be
          // sent to inform users about the updated branch
          break;

        default:
          throw new IOException(rfu.getResult().name());
      }
      recRw = new RevWalk(pdb);
      // Recursive call: update subscribers of the subscriber
      updateSuperProjects(db, Sets.newHashSet(subscriber));
    } catch (IOException e) {
      throw new SubmoduleException("Cannot update gitlinks for " + subscriber.get(), e);
    } finally {
      if (recRw != null) {
        recRw.close();
      }
      if (pdb != null) {
        pdb.close();
      }
    }
  }
  public String getProjectVersion(File repoDir) throws IOException, GitAPIException {
    Git git = Git.open(repoDir);
    Repository repo = git.getRepository();

    // Find base commit between current branch and "master":
    String branch = repo.getBranch();
    RevCommit base = CommitUtils.getBase(repo, "master", branch);
    CommitCountFilter count = new CommitCountFilter();
    CommitFinder finder = new CommitFinder(repo).setFilter(count);
    finder.findBetween(branch, base);
    long commitsSinceBase = count.getCount();

    // Find tags in "master" before base commit:
    RevWalk rw = new RevWalk(repo);
    rw.markStart(base);
    rw.setRetainBody(false);
    Ref master = repo.getRef("master");
    List<Ref> masterAsList = Arrays.asList(master);
    List<Ref> tags = git.tagList().call();
    Map<RevCommit, Ref> masterTags = new HashMap<RevCommit, Ref>();
    for (Ref tag : tags) {
      tag = repo.peel(tag);
      ObjectId commitID = tag.getPeeledObjectId();
      if (commitID == null) continue;
      RevCommit commit = rw.parseCommit(commitID);
      // Only remember tags reachable from "master":
      if (!RevWalkUtils.findBranchesReachableFrom(commit, rw, masterAsList).isEmpty()) {
        masterTags.put(commit, tag);
      }
    }

    // Find the shortest distance in commits between base tag in "master":
    long commitsBetweenBaseAndTag = Long.MAX_VALUE;
    String tagName = "";
    for (RevCommit tagCommit : masterTags.keySet()) {
      count.reset();
      finder.findBetween(base, tagCommit);
      if (count.getCount() < commitsBetweenBaseAndTag) {
        commitsBetweenBaseAndTag = count.getCount();
        tagName = masterTags.get(tagCommit).getName();
      }
    }
    if (commitsBetweenBaseAndTag == Long.MAX_VALUE) {
      // If no tag, get total number of commits:
      commitsBetweenBaseAndTag = repo.getRefDatabase().getRefs("").size();
    }
    long commitsSinceLastMasterTag = commitsSinceBase + commitsBetweenBaseAndTag;

    // Construct version string:
    String version = branch.equals("master") ? "" : (branch + "-");
    if (tagName.startsWith("refs/tags/")) {
      tagName = tagName.substring("refs/tags/".length());
    }
    // v1.1 -> 1.1
    if (tagName.matches("v\\d+.*")) {
      tagName = tagName.substring(1);
    }
    if (tagName.isEmpty()) {
      version = "0";
    }
    version += tagName + ((!tagonly) ? "." + commitsSinceLastMasterTag : "");

    return version;
  }
Example #10
0
  private ListMultimap<SubmitType, ChangeData> validateChangeList(Collection<ChangeData> submitted)
      throws IntegrationException {
    logDebug("Validating {} changes", submitted.size());
    ListMultimap<SubmitType, ChangeData> toSubmit = ArrayListMultimap.create();

    Map<String, Ref> allRefs;
    try {
      allRefs = repo.getRefDatabase().getRefs(ALL);
    } catch (IOException e) {
      throw new IntegrationException(e.getMessage(), e);
    }

    Set<ObjectId> tips = new HashSet<>();
    for (Ref r : allRefs.values()) {
      tips.add(r.getObjectId());
    }

    for (ChangeData cd : submitted) {
      ChangeControl ctl;
      Change chg;
      try {
        ctl = cd.changeControl();
        // Reload change in case index was stale.
        chg = cd.reloadChange();
      } catch (OrmException e) {
        throw new IntegrationException("Failed to validate changes", e);
      }
      Change.Id changeId = cd.getId();
      if (chg.getStatus() != Change.Status.NEW) {
        logDebug("Change {} is not new: {}", changeId, chg.getStatus());
        continue;
      }
      if (chg.currentPatchSetId() == null) {
        logError("Missing current patch set on change " + changeId);
        commits.put(changeId, CodeReviewCommit.noPatchSet(ctl));
        continue;
      }

      PatchSet ps;
      Branch.NameKey destBranch = chg.getDest();
      try {
        ps = cd.currentPatchSet();
      } catch (OrmException e) {
        throw new IntegrationException("Cannot query the database", e);
      }
      if (ps == null || ps.getRevision() == null || ps.getRevision().get() == null) {
        logError("Missing patch set or revision on change " + changeId);
        commits.put(changeId, CodeReviewCommit.noPatchSet(ctl));
        continue;
      }

      String idstr = ps.getRevision().get();
      ObjectId id;
      try {
        id = ObjectId.fromString(idstr);
      } catch (IllegalArgumentException iae) {
        logError("Invalid revision on patch set " + ps.getId());
        commits.put(changeId, CodeReviewCommit.noPatchSet(ctl));
        continue;
      }

      if (!tips.contains(id)) {
        // TODO Technically the proper way to do this test is to use a
        // RevWalk on "$id --not --all" and test for an empty set. But
        // that is way slower than looking for a ref directly pointing
        // at the desired tip. We should always have a ref available.
        //
        // TODO this is actually an error, the branch is gone but we
        // want to merge the issue. We can't safely do that if the
        // tip is not reachable.
        //
        logError(
            "Revision " + idstr + " of patch set " + ps.getId() + " is not contained in any ref");
        commits.put(changeId, CodeReviewCommit.revisionGone(ctl));
        continue;
      }

      CodeReviewCommit commit;
      try {
        commit = rw.parseCommit(id);
      } catch (IOException e) {
        logError("Invalid commit " + idstr + " on patch set " + ps.getId(), e);
        commits.put(changeId, CodeReviewCommit.revisionGone(ctl));
        continue;
      }

      // TODO(dborowitz): Consider putting ChangeData in CodeReviewCommit.
      commit.setControl(ctl);
      commit.setPatchsetId(ps.getId());
      commits.put(changeId, commit);

      MergeValidators mergeValidators = mergeValidatorsFactory.create();
      try {
        mergeValidators.validatePreMerge(repo, commit, destProject, destBranch, ps.getId());
      } catch (MergeValidationException mve) {
        logDebug(
            "Revision {} of patch set {} failed validation: {}",
            idstr,
            ps.getId(),
            mve.getStatus());
        commit.setStatusCode(mve.getStatus());
        continue;
      }

      SubmitType submitType;
      submitType = getSubmitType(commit.getControl(), ps);
      if (submitType == null) {
        logError("No submit type for revision " + idstr + " of patch set " + ps.getId());
        commit.setStatusCode(CommitMergeStatus.NO_SUBMIT_TYPE);
        continue;
      }

      commit.add(canMergeFlag);
      toSubmit.put(submitType, cd);
    }
    logDebug("Submitting on this run: {}", toSubmit);
    return toSubmit;
  }
Example #11
0
 /**
  * Load the current version from the branch.
  *
  * <p>The repository is not held after the call completes, allowing the application to retain this
  * object for long periods of time.
  *
  * @param db repository to access.
  * @throws IOException
  * @throws ConfigInvalidException
  */
 public void load(Repository db) throws IOException, ConfigInvalidException {
   Ref ref = db.getRefDatabase().exactRef(getRefName());
   load(db, ref != null ? ref.getObjectId() : null);
 }