/* * Copyright 2011 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.wicket.pages; import java.text.DateFormat; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.wicket.PageParameters; import org.apache.wicket.behavior.HeaderContributor; import org.apache.wicket.markup.html.basic.Label; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import com.gitblit.GitBlit; import com.gitblit.models.DailyActivity; import com.gitblit.models.Metric; import com.gitblit.models.RefModel; import com.gitblit.models.RepositoryCommit; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.JGitUtils; import com.gitblit.utils.StringUtils; import com.gitblit.utils.TimeUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.charting.GoogleChart; import com.gitblit.wicket.charting.GoogleCharts; import com.gitblit.wicket.charting.GoogleLineChart; import com.gitblit.wicket.charting.GooglePieChart; import com.gitblit.wicket.panels.ActivityPanel; /** * Activity Page shows a list of recent commits across all visible Gitblit * repositories. * * @author James Moger * */ public class ActivityPage extends RootPage { public ActivityPage(PageParameters params) { super(); setupPage("", ""); final UserModel user = GitBlitWebSession.get().getUser(); // parameters int daysBack = WicketUtils.getDaysBack(params); if (daysBack < 1) { daysBack = 14; } String set = WicketUtils.getSet(params); String repositoryName = WicketUtils.getRepositoryName(params); String objectId = WicketUtils.getObject(params); List models = null; if (!StringUtils.isEmpty(repositoryName)) { // named repository models = new ArrayList(); RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName); if (user.canAccessRepository(model)) { models.add(model); } } // get all user accessible repositories if (models == null) { models = GitBlit.self().getRepositoryModels(user); } // filter the repositories by the specified set if (!StringUtils.isEmpty(set)) { List sets = StringUtils.getStringsFromValue(set, ","); List setModels = new ArrayList(); for (RepositoryModel model : models) { for (String curr : sets) { if (model.federationSets.contains(curr)) { setModels.add(model); } } } models = setModels; } // Activity panel shows last daysBack of activity across all // repositories. Date thresholdDate = new Date(System.currentTimeMillis() - daysBack * TimeUtils.ONEDAY); // Build a map of DailyActivity from the available repositories for the // specified threshold date. DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = Calendar.getInstance(); Map activity = new HashMap(); for (RepositoryModel model : models) { if (model.hasCommits && model.lastChange.after(thresholdDate)) { Repository repository = GitBlit.self().getRepository(model.name); List commits = JGitUtils.getRevLog(repository, objectId, thresholdDate); Map> allRefs = JGitUtils.getAllRefs(repository); repository.close(); // determine commit branch String branch = objectId; if (StringUtils.isEmpty(branch)) { List headRefs = allRefs.get(commits.get(0).getId()); List localBranches = new ArrayList(); for (RefModel ref : headRefs) { if (ref.getName().startsWith(Constants.R_HEADS)) { localBranches.add(ref.getName().substring(Constants.R_HEADS.length())); } } // determine branch if (localBranches.size() == 1) { // only one branch, choose it branch = localBranches.get(0); } else if (localBranches.size() > 1) { if (localBranches.contains("master")) { // choose master branch = "master"; } else { // choose first branch branch = localBranches.get(0); } } } for (RevCommit commit : commits) { Date date = JGitUtils.getCommitDate(commit); String dateStr = df.format(date); if (!activity.containsKey(dateStr)) { // Normalize the date to midnight cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); activity.put(dateStr, new DailyActivity(cal.getTime())); } RepositoryCommit commitModel = new RepositoryCommit(model.name, branch, commit); commitModel.setRefs(allRefs.get(commit.getId())); activity.get(dateStr).commits.add(commitModel); } } } // activity metrics Map dayMetrics = new HashMap(); Map repositoryMetrics = new HashMap(); Map authorMetrics = new HashMap(); // prepare day metrics cal.setTimeInMillis(System.currentTimeMillis()); for (int i = 0; i < daysBack; i++) { cal.add(Calendar.DATE, -1); String key = df.format(cal.getTime()); dayMetrics.put(key, new Metric(key)); } // calculate activity metrics for (Map.Entry entry : activity.entrySet()) { // day metrics Metric day = dayMetrics.get(entry.getKey()); day.count = entry.getValue().commits.size(); for (RepositoryCommit commit : entry.getValue().commits) { // repository metrics String repository = commit.repository; if (!repositoryMetrics.containsKey(repository)) { repositoryMetrics.put(repository, new Metric(repository)); } repositoryMetrics.get(repository).count++; // author metrics String author = commit.getAuthorIdent().getEmailAddress().toLowerCase(); if (!authorMetrics.containsKey(author)) { authorMetrics.put(author, new Metric(author)); } authorMetrics.get(author).count++; } } // sort the activity groups and their commit contents int totalCommits = 0; List recentActivity = new ArrayList(activity.values()); for (DailyActivity daily : recentActivity) { Collections.sort(daily.commits); totalCommits += daily.commits.size(); } // build google charts int w = 310; int h = 150; GoogleCharts charts = new GoogleCharts(); // sort in reverse-chronological order and then reverse that Collections.sort(recentActivity); Collections.reverse(recentActivity); // daily line chart GoogleChart chart = new GoogleLineChart("chartDaily", getString("gb.dailyActivity"), "day", getString("gb.commits")); df = new SimpleDateFormat("MMM dd"); for (DailyActivity metric : recentActivity) { chart.addValue(df.format(metric.date), metric.commits.size()); } chart.setWidth(w); chart.setHeight(h); charts.addChart(chart); // active repositories pie chart chart = new GooglePieChart("chartRepositories", getString("gb.activeRepositories"), getString("gb.repository"), getString("gb.commits")); for (Metric metric : repositoryMetrics.values()) { chart.addValue(metric.name, metric.count); } chart.setWidth(w); chart.setHeight(h); charts.addChart(chart); // active authors pie chart chart = new GooglePieChart("chartAuthors", getString("gb.activeAuthors"), getString("gb.author"), getString("gb.commits")); for (Metric metric : authorMetrics.values()) { chart.addValue(metric.name, metric.count); } chart.setWidth(w); chart.setHeight(h); charts.addChart(chart); add(new HeaderContributor(charts)); add(new Label("subheader", MessageFormat.format(getString("gb.recentActivitySubheader"), daysBack, totalCommits, authorMetrics.size()))); // add activity panel add(new ActivityPanel("activityPanel", recentActivity)); } }