com.gitblit.plugin.flowdock.FlowDockReceiveHook.java Source code

Java tutorial

Introduction

Here is the source code for com.gitblit.plugin.flowdock.FlowDockReceiveHook.java

Source

/*
 * Copyright 2014 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.plugin.flowdock;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevSort;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ro.fortsoft.pf4j.Extension;

import com.gitblit.Constants;
import com.gitblit.Keys;
import com.gitblit.extensions.ReceiveHook;
import com.gitblit.git.GitblitReceivePack;
import com.gitblit.manager.IRuntimeManager;
import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.RepositoryModel;
import com.gitblit.plugin.flowdock.GitPayload.Commit;
import com.gitblit.plugin.flowdock.GitPayload.Ident;
import com.gitblit.servlet.GitblitContext;
import com.gitblit.utils.JGitUtils;

/**
 * This hook will post a message to a room when a ref is updated.
 *
 * @author James Moger
 *
 */
@Extension
public class FlowDockReceiveHook extends ReceiveHook {

    final String name = getClass().getSimpleName();

    final Logger log = LoggerFactory.getLogger(getClass());

    final FlowDock flowdock;

    public FlowDockReceiveHook() {
        super();

        IRuntimeManager runtimeManager = GitblitContext.getManager(IRuntimeManager.class);
        FlowDock.init(runtimeManager);
        flowdock = FlowDock.instance();
    }

    @Override
    public void onPreReceive(GitblitReceivePack receivePack, Collection<ReceiveCommand> commands) {
        // NOOP
    }

    @Override
    public void onPostReceive(GitblitReceivePack receivePack, Collection<ReceiveCommand> commands) {
        if (!shallPost(receivePack, commands)) {
            return;
        }

        IRuntimeManager runtimeManager = GitblitContext.getManager(IRuntimeManager.class);
        try {
            for (ReceiveCommand cmd : commands) {
                if (cmd.getRefName().startsWith(Constants.R_TAGS)) {
                    boolean shallPostTag = runtimeManager.getSettings().getBoolean(Plugin.SETTING_POST_TAGS, true);
                    if (!shallPostTag) {
                        continue;
                    }
                } else if (cmd.getRefName().startsWith(Constants.R_HEADS)) {
                    boolean shallPostBranch = runtimeManager.getSettings().getBoolean(Plugin.SETTING_POST_BRANCHES,
                            true);
                    if (!shallPostBranch) {
                        continue;
                    }
                } else {
                    // ignore other refs
                    continue;
                }

                RepositoryModel repo = receivePack.getRepositoryModel();

                String repoUrl = getUrl(repo.name, null, null);
                String diffUrl = getUrl(repo.name, cmd.getOldId().getName(), cmd.getNewId().getName());

                GitPayload payload = new GitPayload().pusher(receivePack.getUserModel()).repository(repo.name)
                        .repoUrl(repoUrl).tags(getTags(repo)).ref(cmd.getRefName())
                        .refName(Repository.shortenRefName(cmd.getRefName())).diffUrl(diffUrl)
                        .before(cmd.getOldId().getName()).after(cmd.getNewId().getName());

                List<RevCommit> commits = getCommits(receivePack, cmd.getOldId().name(), cmd.getNewId().name());
                for (RevCommit commit : commits) {
                    Commit c = new Commit();
                    c.id = commit.getName();
                    c.url = getUrl(repo.name, null, commit.getName());
                    c.message = commit.getFullMessage().trim();

                    PersonIdent author = commit.getAuthorIdent();
                    c.author = new Ident(author.getName(), author.getEmailAddress());
                    c.timestamp = author.getWhen();
                    if (c.timestamp == null) {
                        c.timestamp = commit.getCommitterIdent().getWhen();
                    }

                    List<PathChangeModel> paths = JGitUtils.getFilesInCommit(receivePack.getRepository(), commit);
                    c.added = filter(paths, ChangeType.ADD);
                    c.modified = filter(paths, ChangeType.MODIFY);
                    c.removed = filter(paths, ChangeType.DELETE);

                    payload.add(c);
                }

                flowdock.setFlow(repo, payload);
                flowdock.sendAsync(payload);
            }
        } catch (Exception e) {
            log.error("Failed to notify FlowDock!", e);
        }
    }

    /**
     * Determine if the ref changes for this repository should be posted to FlowDock.
     *
     * @param receivePack
     * @return true if the ref changes should be posted
     */
    protected boolean shallPost(GitblitReceivePack receivePack, Collection<ReceiveCommand> commands) {
        boolean shallPostRepo = flowdock.shallPost(receivePack.getRepositoryModel());
        return shallPostRepo;
    }

    protected String getSource(RepositoryModel repository) {
        return Constants.NAME;
    }

    protected List<String> getTags(RepositoryModel repository) {
        IRuntimeManager runtimeManager = GitblitContext.getManager(IRuntimeManager.class);
        List<String> tags = new ArrayList<String>();
        tags.addAll(runtimeManager.getSettings().getStrings(Plugin.SETTING_FIXED_COMMIT_TAGS));
        if (tags.isEmpty()) {
            return null;
        }
        return tags;
    }

    /**
     * Returns a link appropriate for the push.
     *
     * If both new and old ids are null, the summary page link is returned.
     *
     * @param repo
     * @param oldId
     * @param newId
     * @return a link
     */
    protected String getUrl(String repo, String oldId, String newId) {
        IRuntimeManager runtimeManager = GitblitContext.getManager(IRuntimeManager.class);
        String canonicalUrl = runtimeManager.getSettings().getString(Keys.web.canonicalUrl,
                "https://localhost:8443");

        if (oldId == null && newId != null) {
            // create
            final String hrefPattern = "{0}/commit?r={1}&h={2}";
            return MessageFormat.format(hrefPattern, canonicalUrl, repo, newId);
        } else if (oldId != null && newId == null) {
            // log
            final String hrefPattern = "{0}/log?r={1}&h={2}";
            return MessageFormat.format(hrefPattern, canonicalUrl, repo, oldId);
        } else if (oldId != null && newId != null) {
            // update/compare
            final String hrefPattern = "{0}/compare?r={1}&h={2}..{3}";
            return MessageFormat.format(hrefPattern, canonicalUrl, repo, oldId, newId);
        } else if (oldId == null && newId == null) {
            // summary page
            final String hrefPattern = "{0}/summary?r={1}";
            return MessageFormat.format(hrefPattern, canonicalUrl, repo);
        }

        return null;
    }

    private List<RevCommit> getCommits(GitblitReceivePack receivePack, String baseId, String tipId) {
        List<RevCommit> list = new ArrayList<RevCommit>();
        RevWalk walk = receivePack.getRevWalk();
        walk.reset();
        walk.sort(RevSort.TOPO);
        try {
            RevCommit tip = walk.parseCommit(receivePack.getRepository().resolve(tipId));
            RevCommit base = walk.parseCommit(receivePack.getRepository().resolve(baseId));
            walk.markStart(tip);
            walk.markUninteresting(base);
            for (;;) {
                RevCommit c = walk.next();
                if (c == null) {
                    break;
                }
                list.add(c);
            }
        } catch (IOException e) {
            // Should never happen, the core receive process would have
            // identified the missing object earlier before we got control.
            log.error("failed to get commits", e);
        } finally {
            walk.release();
        }
        return list;
    }

    private List<String> filter(List<PathChangeModel> paths, ChangeType ct) {
        List<String> list = new ArrayList<String>();
        for (PathChangeModel path : paths) {
            switch (path.changeType) {
            case ADD:
            case COPY:
                if (ChangeType.ADD == ct) {
                    list.add(path.path);
                }
                break;
            case DELETE:
                if (ChangeType.DELETE == ct) {
                    list.add(path.path);
                }
                break;
            default:
                if (ChangeType.MODIFY == ct) {
                    list.add(path.path);
                }
                break;
            }
        }
        return list;
    }
}