package org.apache.maven.plugin.changelog; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ import org.apache.maven.doxia.sink.Sink; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.scm.ChangeFile; import org.apache.maven.scm.ChangeSet; import org.apache.maven.scm.command.changelog.ChangeLogSet; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; /** * Generate a developer activity report. * * @version $Id$ */ @Mojo( name = "dev-activity" ) public class DeveloperActivityReport extends ChangeLogReport { /** * Used to hold data while creating the report */ private Map<String, List<ChangeSet>> commits; private Map<String, Map<String, ChangeFile>> files; /** * {@inheritDoc} */ public String getDescription( Locale locale ) { return getBundle( locale ).getString( "report.dev-activity.description" ); } /** * {@inheritDoc} */ public String getName( Locale locale ) { return getBundle( locale ).getString( "report.dev-activity.name" ); } /** * {@inheritDoc} */ public String getOutputName() { return "dev-activity"; } /** * {@inheritDoc} */ protected void doGenerateEmptyReport( ResourceBundle bundle, Sink sink ) { sink.head(); sink.title(); sink.text( bundle.getString( "report.dev-activity.header" ) ); sink.title_(); sink.head_(); sink.body(); sink.section1(); sink.sectionTitle1(); sink.text( bundle.getString( "report.dev-activity.mainTitle" ) ); sink.sectionTitle1_(); sink.paragraph(); sink.text( "No sources found to create a report." ); sink.paragraph_(); sink.section1_(); sink.body_(); sink.flush(); sink.close(); } /** * {@inheritDoc} */ protected void doGenerateReport( List<ChangeLogSet> changeLogSets, ResourceBundle bundle, Sink sink ) { sink.head(); sink.title(); sink.text( bundle.getString( "report.dev-activity.header" ) ); sink.title_(); sink.head_(); sink.body(); sink.section1(); sink.sectionTitle1(); sink.text( bundle.getString( "report.dev-activity.mainTitle" ) ); sink.sectionTitle1_(); if ( developers.isEmpty() ) { sink.paragraph(); sink.text( bundle.getString( "report.dev-activity.noDevelopers" ) ); sink.paragraph_(); } else { for ( ChangeLogSet set : changeLogSets ) { doChangedSets( set, bundle, sink ); } } sink.section1_(); sink.body_(); sink.flush(); sink.close(); } /** * generates a section of the report referring to a changeset * * @param set the current ChangeSet to generate this section of the report * @param bundle the resource bundle to retrieve report phrases from * @param sink the report formatting tool */ private void doChangedSets( ChangeLogSet set, ResourceBundle bundle, Sink sink ) { sink.section2(); doChangeSetTitle( set, bundle, sink ); doSummary( set, bundle, sink ); sink.table(); sink.tableRow(); sink.tableHeaderCell(); sink.text( bundle.getString( "report.dev-activity.developer" ) ); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text( bundle.getString( "report.TotalCommits" ) ); sink.tableHeaderCell_(); sink.tableHeaderCell(); sink.text( bundle.getString( "report.dev-activity.filesChanged" ) ); sink.tableHeaderCell_(); sink.tableRow_(); doDeveloperRows( set, sink ); sink.table_(); sink.section2_(); } /** * generates the report section table of the developers * * @param set change log set generate the developer activity * @param sink the report formatting tool */ private void doDeveloperRows( ChangeLogSet set, Sink sink ) { initDeveloperDetails( set ); for ( Map.Entry<String, List<ChangeSet>> commit : commits.entrySet() ) { String author = commit.getKey(); List<ChangeSet> devCommits = commit.getValue(); Map<String, ChangeFile> devFiles = files.get( author ); sink.tableRow(); sink.tableCell(); sinkAuthorDetails( sink, author ); sink.tableCell_(); sink.tableCell(); sink.text( String.valueOf( devCommits.size() ) ); sink.tableCell_(); sink.tableCell(); sink.text( String.valueOf( devFiles.size() ) ); sink.tableCell_(); sink.tableRow_(); } } /** * counts the number of commits and files changed for each developer * * @param set the change log set to generate the developer details from */ private void initDeveloperDetails( ChangeLogSet set ) { commits = new HashMap<String, List<ChangeSet>>(); files = new HashMap<String, Map<String, ChangeFile>>(); countDevCommits( set.getChangeSets() ); countDevFiles( set.getChangeSets() ); } /** * counts the number of commits of each developer * * @param entries the change log entries used to search and count developer commits */ private void countDevCommits( Collection<ChangeSet> entries ) { for ( ChangeSet entry : entries ) { String developer = entry.getAuthor(); List<ChangeSet> list = commits.get( developer ); if ( list == null ) { list = new LinkedList<ChangeSet>(); commits.put( developer, list ); } list.add( entry ); } } /** * counts the number of files changed by each developer * * @param entries the change log entries used to search and count file changes */ private void countDevFiles( Collection<ChangeSet> entries ) { for ( ChangeSet entry : entries ) { String developer = entry.getAuthor(); Map<String, ChangeFile> filesMap = files.get( developer ); if ( filesMap == null ) { filesMap = new HashMap<String, ChangeFile>(); files.put( developer, filesMap ); } for ( ChangeFile file : entry.getFiles() ) { filesMap.put( file.getName(), file ); } } } }