Package com.gitblit.git

Source Code of com.gitblit.git.PatchsetCommand

/*
* Copyright 2013 gitblit.com.
*
* 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.gitblit.git;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.ReceiveCommand;

import com.gitblit.Constants;
import com.gitblit.models.TicketModel;
import com.gitblit.models.TicketModel.Change;
import com.gitblit.models.TicketModel.Field;
import com.gitblit.models.TicketModel.Patchset;
import com.gitblit.models.TicketModel.PatchsetType;
import com.gitblit.models.TicketModel.Status;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.StringUtils;

/**
*
* A subclass of ReceiveCommand which constructs a ticket change based on a
* patchset and data derived from the push ref.
*
* @author James Moger
*
*/
public class PatchsetCommand extends ReceiveCommand {

  public static final String TOPIC = "t=";

  public static final String RESPONSIBLE = "r=";

  public static final String WATCH = "cc=";

  public static final String MILESTONE = "m=";

  protected final Change change;

  protected boolean isNew;

  protected long ticketId;

  public static String getBasePatchsetBranch(long ticketNumber) {
    StringBuilder sb = new StringBuilder();
    sb.append(Constants.R_TICKETS_PATCHSETS);
    long m = ticketNumber % 100L;
    if (m < 10) {
      sb.append('0');
    }
    sb.append(m);
    sb.append('/');
    sb.append(ticketNumber);
    sb.append('/');
    return sb.toString();
  }

  public static String getTicketBranch(long ticketNumber) {
    return Constants.R_TICKET + ticketNumber;
  }

  public static String getReviewBranch(long ticketNumber) {
    return "ticket-" + ticketNumber;
  }

  public static String getPatchsetBranch(long ticketId, long patchset) {
    return getBasePatchsetBranch(ticketId) + patchset;
  }

  public static long getTicketNumber(String ref) {
    if (ref.startsWith(Constants.R_TICKETS_PATCHSETS)) {
      // patchset revision

      // strip changes ref
      String p = ref.substring(Constants.R_TICKETS_PATCHSETS.length());
      // strip shard id
      p = p.substring(p.indexOf('/') + 1);
      // strip revision
      p = p.substring(0, p.indexOf('/'));
      // parse ticket number
      return Long.parseLong(p);
    } else if (ref.startsWith(Constants.R_TICKET)) {
      String p = ref.substring(Constants.R_TICKET.length());
      // parse ticket number
      return Long.parseLong(p);
    }
    return 0L;
  }

  public PatchsetCommand(String username, Patchset patchset) {
    super(patchset.isFF() ? ObjectId.fromString(patchset.parent) : ObjectId.zeroId(),
        ObjectId.fromString(patchset.tip), null);
    this.change = new Change(username);
    this.change.patchset = patchset;
  }

  public PatchsetType getPatchsetType() {
    return change.patchset.type;
  }

  public boolean isNewTicket() {
    return isNew;
  }

  public long getTicketId() {
    return ticketId;
  }

  public Change getChange() {
    return change;
  }

  /**
   * Creates a "new ticket" change for the proposal.
   *
   * @param commit
   * @param mergeTo
   * @param ticketId
   * @parem pushRef
   */
  public void newTicket(RevCommit commit, String mergeTo, long ticketId, String pushRef) {
    this.ticketId = ticketId;
    isNew = true;
    change.setField(Field.title, getTitle(commit));
    change.setField(Field.body, getBody(commit));
    change.setField(Field.status, Status.New);
    change.setField(Field.mergeTo, mergeTo);
    change.setField(Field.type, TicketModel.Type.Proposal);

    Set<String> watchSet = new TreeSet<String>();
    watchSet.add(change.author);

    // identify parameters passed in the push ref
    if (!StringUtils.isEmpty(pushRef)) {
      List<String> watchers = getOptions(pushRef, WATCH);
      if (!ArrayUtils.isEmpty(watchers)) {
        for (String cc : watchers) {
          watchSet.add(cc.toLowerCase());
        }
      }

      String milestone = getSingleOption(pushRef, MILESTONE);
      if (!StringUtils.isEmpty(milestone)) {
        // user provided milestone
        change.setField(Field.milestone, milestone);
      }

      String responsible = getSingleOption(pushRef, RESPONSIBLE);
      if (!StringUtils.isEmpty(responsible)) {
        // user provided responsible
        change.setField(Field.responsible, responsible);
        watchSet.add(responsible);
      }

      String topic = getSingleOption(pushRef, TOPIC);
      if (!StringUtils.isEmpty(topic)) {
        // user provided topic
        change.setField(Field.topic, topic);
      }
    }

    // set the watchers
    change.watch(watchSet.toArray(new String[watchSet.size()]));
  }

  /**
   *
   * @param commit
   * @param mergeTo
   * @param ticket
   * @param pushRef
   */
  public void updateTicket(RevCommit commit, String mergeTo, TicketModel ticket, String pushRef) {

    this.ticketId = ticket.number;

    if (ticket.isClosed()) {
      // re-opening a closed ticket
      change.setField(Field.status, Status.Open);
    }

    // ticket may or may not already have an integration branch
    if (StringUtils.isEmpty(ticket.mergeTo) || !ticket.mergeTo.equals(mergeTo)) {
      change.setField(Field.mergeTo, mergeTo);
    }

    if (ticket.isProposal() && change.patchset.commits == 1 && change.patchset.type.isRewrite()) {

      // Gerrit-style title and description updates from the commit
      // message
      String title = getTitle(commit);
      String body = getBody(commit);

      if (!ticket.title.equals(title)) {
        // title changed
        change.setField(Field.title, title);
      }

      if (!ticket.body.equals(body)) {
        // description changed
        change.setField(Field.body, body);
      }
    }

    Set<String> watchSet = new TreeSet<String>();
    watchSet.add(change.author);

    // update the patchset command metadata
    if (!StringUtils.isEmpty(pushRef)) {
      List<String> watchers = getOptions(pushRef, WATCH);
      if (!ArrayUtils.isEmpty(watchers)) {
        for (String cc : watchers) {
          watchSet.add(cc.toLowerCase());
        }
      }

      String milestone = getSingleOption(pushRef, MILESTONE);
      if (!StringUtils.isEmpty(milestone) && !milestone.equals(ticket.milestone)) {
        // user specified a (different) milestone
        change.setField(Field.milestone, milestone);
      }

      String responsible = getSingleOption(pushRef, RESPONSIBLE);
      if (!StringUtils.isEmpty(responsible) && !responsible.equals(ticket.responsible)) {
        // user specified a (different) responsible
        change.setField(Field.responsible, responsible);
        watchSet.add(responsible);
      }

      String topic = getSingleOption(pushRef, TOPIC);
      if (!StringUtils.isEmpty(topic) && !topic.equals(ticket.topic)) {
        // user specified a (different) topic
        change.setField(Field.topic, topic);
      }
    }

    // update the watchers
    watchSet.removeAll(ticket.getWatchers());
    if (!watchSet.isEmpty()) {
      change.watch(watchSet.toArray(new String[watchSet.size()]));
    }
  }

  @Override
  public String getRefName() {
    return getPatchsetBranch();
  }

  public String getPatchsetBranch() {
    return getBasePatchsetBranch(ticketId) + change.patchset.number;
  }

  public String getTicketBranch() {
    return getTicketBranch(ticketId);
  }

  private String getTitle(RevCommit commit) {
    String title = commit.getShortMessage();
    return title;
  }

  /**
   * Returns the body of the commit message
   *
   * @return
   */
  private String getBody(RevCommit commit) {
    String body = commit.getFullMessage().substring(commit.getShortMessage().length()).trim();
    return body;
  }

  /** Extracts a ticket field from the ref name */
  private static List<String> getOptions(String refName, String token) {
    if (refName.indexOf('%') > -1) {
      List<String> list = new ArrayList<String>();
      String [] strings = refName.substring(refName.indexOf('%') + 1).split(",");
      for (String str : strings) {
        if (str.toLowerCase().startsWith(token)) {
          String val = str.substring(token.length());
          list.add(val);
        }
      }
      return list;
    }
    return null;
  }

  /** Extracts a ticket field from the ref name */
  private static String getSingleOption(String refName, String token) {
    List<String> list = getOptions(refName, token);
    if (list != null && list.size() > 0) {
      return list.get(0);
    }
    return null;
  }

  /** Extracts a ticket field from the ref name */
  public static String getSingleOption(ReceiveCommand cmd, String token) {
    return getSingleOption(cmd.getRefName(), token);
  }

  /** Extracts a ticket field from the ref name */
  public static List<String> getOptions(ReceiveCommand cmd, String token) {
    return getOptions(cmd.getRefName(), token);
  }

}
TOP

Related Classes of com.gitblit.git.PatchsetCommand

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.