You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sj...@apache.org on 2025/02/23 15:17:05 UTC
(maven-project-info-reports-plugin) branch master updated: [MPIR-478] Allow to save avatars images for team report during project build
This is an automated email from the ASF dual-hosted git repository.
sjaranowski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-project-info-reports-plugin.git
The following commit(s) were added to refs/heads/master by this push:
new e51cef8 [MPIR-478] Allow to save avatars images for team report during project build
e51cef8 is described below
commit e51cef80148c7fc79d53325275589f9f41702ca8
Author: Slawomir Jaranowski <s....@gmail.com>
AuthorDate: Thu Feb 20 22:49:37 2025 +0100
[MPIR-478] Allow to save avatars images for team report during project build
---
pom.xml | 4 +-
src/it/team-local-avatars/pom.xml | 82 ++++++++++
.../team-local-avatars/verify.groovy} | 18 +--
.../maven/report/projectinfo/TeamReport.java | 179 +++++++++++++--------
.../projectinfo/avatars/AvatarsProvider.java | 59 +++++++
.../projectinfo/avatars/GravatarProvider.java | 156 ++++++++++++++++++
.../report/projectinfo/avatars/default-avatar.jpg | Bin 0 -> 129 bytes
.../maven/report/projectinfo/TeamReportTest.java | 3 +
.../projectinfo/avatars/GravatarProviderTest.java | 92 +++++++++++
.../maven/report/projectinfo/stubs/TeamStub.java | 15 ++
10 files changed, 524 insertions(+), 84 deletions(-)
diff --git a/pom.xml b/pom.xml
index 3f3732e..cd81f6e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@ under the License.
</parent>
<artifactId>maven-project-info-reports-plugin</artifactId>
- <version>3.8.1-SNAPSHOT</version>
+ <version>3.9.0-SNAPSHOT</version>
<packaging>maven-plugin</packaging>
<name>Apache Maven Project Info Reports Plugin</name>
@@ -123,7 +123,7 @@ under the License.
<sitePluginVersion>3.21.0</sitePluginVersion>
<fluidoSkinVersion>2.0.1</fluidoSkinVersion>
<checkstyle.violation.ignore>ParameterNumber,MethodLength</checkstyle.violation.ignore>
- <project.build.outputTimestamp>2024-10-18T09:42:43Z</project.build.outputTimestamp>
+ <project.build.outputTimestamp>2025-02-19T22:31:07Z</project.build.outputTimestamp>
</properties>
<dependencies>
diff --git a/src/it/team-local-avatars/pom.xml b/src/it/team-local-avatars/pom.xml
new file mode 100644
index 0000000..3b068eb
--- /dev/null
+++ b/src/it/team-local-avatars/pom.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.plugins.project-info-reports</groupId>
+ <artifactId>team-local-avatars</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ </properties>
+
+ <developers>
+ <developer>
+ <id>one-id</id>
+ <name>one-name</name>
+ <email>sjaranowski@apache.org</email>
+ </developer>
+ <developer>
+ <id>two-id</id>
+ <name>two-name</name>
+ </developer>
+ <developer>
+ <id>three-id</id>
+ <name>three-name</name>
+ <email>email3@ecample.com</email>
+ </developer>
+ </developers>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>@sitePluginVersion@</version>
+ </plugin>
+ </plugins>
+ </build>
+
+ <reporting>
+ <excludeDefaults>true</excludeDefaults>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <externalAvatarImages>false</externalAvatarImages>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>team</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
diff --git a/src/test/java/org/apache/maven/report/projectinfo/stubs/TeamStub.java b/src/it/team-local-avatars/verify.groovy
similarity index 64%
copy from src/test/java/org/apache/maven/report/projectinfo/stubs/TeamStub.java
copy to src/it/team-local-avatars/verify.groovy
index 63d0e7b..aabeac8 100644
--- a/src/test/java/org/apache/maven/report/projectinfo/stubs/TeamStub.java
+++ b/src/it/team-local-avatars/verify.groovy
@@ -16,15 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.maven.report.projectinfo.stubs;
-/**
- * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
- * @version $Id$
- */
-public class TeamStub extends ProjectInfoProjectStub {
- @Override
- protected String getPOM() {
- return "team-plugin-config.xml";
- }
-}
+def team = new File( basedir, 'target/site/team.html' ).text
+
+assert team.count('<figure><img src="avatars/90cc13b765c79d2d55ca64388ea2bc5f.jpg" /></figure>') == 1
+assert team.count('<figure><img src="avatars/00000000000000000000000000000000.jpg" /></figure>') == 2
+
+assert new File(basedir, 'target/site/avatars/90cc13b765c79d2d55ca64388ea2bc5f.jpg').exists()
+assert new File(basedir, 'target/site/avatars/00000000000000000000000000000000.jpg').exists()
diff --git a/src/main/java/org/apache/maven/report/projectinfo/TeamReport.java b/src/main/java/org/apache/maven/report/projectinfo/TeamReport.java
index 5fb6bda..3b93a1c 100644
--- a/src/main/java/org/apache/maven/report/projectinfo/TeamReport.java
+++ b/src/main/java/org/apache/maven/report/projectinfo/TeamReport.java
@@ -20,9 +20,9 @@ package org.apache.maven.report.projectinfo;
import javax.inject.Inject;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -32,10 +32,11 @@ import java.util.Properties;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.model.Contributor;
import org.apache.maven.model.Developer;
-import org.apache.maven.model.Model;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.report.projectinfo.avatars.AvatarsProvider;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.i18n.I18N;
@@ -52,19 +53,51 @@ public class TeamReport extends AbstractProjectInfoReport {
/**
* Shows avatar images for team members that have a) properties/picUrl set b) An avatar at gravatar.com for their
* email address
- * <p/>
- * Future versions of this plugin may implement different strategies for resolving avatar images, possibly
- * using different providers.
- *<p>
- *<strong>Note</strong>: This property will be renamed to {@code tteam.showAvatarImages} in 3.0.
+ *
* @since 2.6
*/
@Parameter(property = "teamlist.showAvatarImages", defaultValue = "true")
private boolean showAvatarImages;
+ /**
+ * Indicate if URL should be used for avatar images.
+ * <p>
+ * If set to <code>false</code> images will be downloaded and attached to report during build.
+ * Local path will be used for images.
+ *
+ * @since 3.9.0
+ */
+ @Parameter(property = "teamlist.externalAvatarImages", defaultValue = "true")
+ private boolean externalAvatarImages;
+
+ /**
+ * Base URL for avatar provider.
+ *
+ * @since 3.9.0
+ */
+ @Parameter(property = "teamlist.avatarBaseUrl", defaultValue = "https://www.gravatar.com/avatar/")
+ private String avatarBaseUrl;
+
+ /**
+ * Provider name for avatar images.
+ * <p>
+ * Report has one implementation for gravatar.com. Users can provide other by implementing {@link AvatarsProvider}.
+ *
+ * @since 3.9.0
+ */
+ @Parameter(property = "teamlist.avatarProviderName", defaultValue = "gravatar")
+ private String avatarProviderName;
+
+ private final Map<String, AvatarsProvider> avatarsProviders;
+
@Inject
- public TeamReport(RepositorySystem repositorySystem, I18N i18n, ProjectBuilder projectBuilder) {
+ public TeamReport(
+ RepositorySystem repositorySystem,
+ I18N i18n,
+ ProjectBuilder projectBuilder,
+ Map<String, AvatarsProvider> avatarsProviders) {
super(repositorySystem, i18n, projectBuilder);
+ this.avatarsProviders = avatarsProviders;
}
// ----------------------------------------------------------------------
@@ -83,10 +116,55 @@ public class TeamReport extends AbstractProjectInfoReport {
}
@Override
- public void executeReport(Locale locale) {
- ProjectTeamRenderer r =
- new ProjectTeamRenderer(getSink(), project.getModel(), getI18N(locale), locale, showAvatarImages);
- r.render();
+ public void executeReport(Locale locale) throws MavenReportException {
+
+ Map<Contributor, String> avatarImages = prepareAvatars();
+
+ ProjectTeamRenderer renderer =
+ new ProjectTeamRenderer(getSink(), project, getI18N(locale), locale, showAvatarImages, avatarImages);
+ renderer.render();
+ }
+
+ private Map<Contributor, String> prepareAvatars() throws MavenReportException {
+
+ if (!showAvatarImages) {
+ return Collections.emptyMap();
+ }
+
+ AvatarsProvider avatarsProvider = avatarsProviders.get(avatarProviderName);
+ if (avatarsProvider == null) {
+ throw new MavenReportException("No AvatarsProvider found for name " + avatarProviderName);
+ }
+ avatarsProvider.setBaseUrl(avatarBaseUrl);
+ avatarsProvider.setOutputDirectory(getReportOutputDirectory());
+
+ Map<Contributor, String> result = new HashMap<>();
+ try {
+ prepareContributorAvatars(result, avatarsProvider, project.getDevelopers());
+ prepareContributorAvatars(result, avatarsProvider, project.getContributors());
+ } catch (IOException e) {
+ throw new MavenReportException("Unable to load avatar images", e);
+ }
+ return result;
+ }
+
+ private void prepareContributorAvatars(
+ Map<Contributor, String> avatarImages,
+ AvatarsProvider avatarsProvider,
+ List<? extends Contributor> contributors)
+ throws IOException {
+
+ for (Contributor contributor : contributors) {
+
+ String picSource = contributor.getProperties().getProperty("picUrl");
+ if (picSource == null || picSource.isEmpty()) {
+ picSource = externalAvatarImages
+ ? avatarsProvider.getAvatarUrl(contributor.getEmail())
+ : avatarsProvider.getLocalAvatarPath(contributor.getEmail());
+ }
+
+ avatarImages.put(contributor, picSource);
+ }
}
/**
@@ -130,24 +208,24 @@ public class TeamReport extends AbstractProjectInfoReport {
private static final String ID = "id";
- private final Model model;
+ private final MavenProject mavenProject;
private final boolean showAvatarImages;
- private final String protocol;
+ private final Map<Contributor, String> avatarImages;
- ProjectTeamRenderer(Sink sink, Model model, I18N i18n, Locale locale, boolean showAvatarImages) {
+ ProjectTeamRenderer(
+ Sink sink,
+ MavenProject mavenProject,
+ I18N i18n,
+ Locale locale,
+ boolean showAvatarImages,
+ Map<Contributor, String> avatarImages) {
super(sink, i18n, locale);
- this.model = model;
+ this.mavenProject = mavenProject;
this.showAvatarImages = showAvatarImages;
-
- // prepare protocol for gravatar
- if (model.getUrl() != null && model.getUrl().startsWith("https://")) {
- this.protocol = "https";
- } else {
- this.protocol = "http";
- }
+ this.avatarImages = avatarImages;
}
@Override
@@ -164,11 +242,11 @@ public class TeamReport extends AbstractProjectInfoReport {
paragraph(getI18nString("intro.description2"));
// Developer section
- List<Developer> developers = model.getDevelopers();
+ List<Developer> developers = mavenProject.getDevelopers();
startSection(getI18nString("developers.title"));
- if (isEmpty(developers)) {
+ if (developers.isEmpty()) {
paragraph(getI18nString("nodeveloper"));
} else {
paragraph(getI18nString("developers.intro"));
@@ -191,11 +269,11 @@ public class TeamReport extends AbstractProjectInfoReport {
endSection();
// contributors section
- List<Contributor> contributors = model.getContributors();
+ List<Contributor> contributors = mavenProject.getContributors();
startSection(getI18nString("contributors.title"));
- if (isEmpty(contributors)) {
+ if (contributors.isEmpty()) {
paragraph(getI18nString("nocontributor"));
} else {
paragraph(getI18nString("contributors.intro"));
@@ -223,17 +301,9 @@ public class TeamReport extends AbstractProjectInfoReport {
sink.tableRow();
if (headersMap.get(IMAGE) == Boolean.TRUE && showAvatarImages) {
- Properties properties = member.getProperties();
- String picUrl = properties.getProperty("picUrl");
- if (picUrl == null || picUrl.isEmpty()) {
- picUrl = getGravatarUrl(member.getEmail());
- }
- if (picUrl == null || picUrl.isEmpty()) {
- picUrl = getSpacerGravatarUrl();
- }
sink.tableCell();
sink.figure();
- sink.figureGraphics(picUrl);
+ sink.figureGraphics(avatarImages.get(member));
sink.figure_();
sink.tableCell_();
}
@@ -288,35 +358,6 @@ public class TeamReport extends AbstractProjectInfoReport {
sink.tableRow_();
}
- private static final String AVATAR_SIZE = "s=60";
-
- private String getSpacerGravatarUrl() {
- return protocol + "://www.gravatar.com/avatar/00000000000000000000000000000000?d=blank&f=y&" + AVATAR_SIZE;
- }
-
- private String getGravatarUrl(String email) {
- if (email == null) {
- return null;
- }
- email = StringUtils.trim(email);
- email = email.toLowerCase();
- MessageDigest md;
- try {
- md = MessageDigest.getInstance("MD5");
- md.update(email.getBytes());
- byte[] byteData = md.digest();
- StringBuilder sb = new StringBuilder();
- final int lowerEightBitsOnly = 0xff;
- for (byte aByteData : byteData) {
- sb.append(Integer.toString((aByteData & lowerEightBitsOnly) + 0x100, 16)
- .substring(1));
- }
- return protocol + "://www.gravatar.com/avatar/" + sb.toString() + "?d=mm&" + AVATAR_SIZE;
- } catch (NoSuchAlgorithmException e) {
- return null;
- }
- }
-
private String[] getRequiredContrHeaderArray(Map<String, Boolean> requiredHeaders) {
List<String> requiredArray = new ArrayList<>();
String image = getI18nString("contributors.image");
@@ -461,7 +502,7 @@ public class TeamReport extends AbstractProjectInfoReport {
if (StringUtils.isNotEmpty(unit.getOrganizationUrl())) {
requiredHeaders.put(ORGANIZATION_URL, Boolean.TRUE);
}
- if (!isEmpty(unit.getRoles())) {
+ if (!unit.getRoles().isEmpty()) {
requiredHeaders.put(ROLES, Boolean.TRUE);
}
if (StringUtils.isNotEmpty(unit.getTimezone())) {
@@ -494,9 +535,5 @@ public class TeamReport extends AbstractProjectInfoReport {
sink.tableCell_();
}
-
- private static boolean isEmpty(List<?> list) {
- return (list == null) || list.isEmpty();
- }
}
}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/avatars/AvatarsProvider.java b/src/main/java/org/apache/maven/report/projectinfo/avatars/AvatarsProvider.java
new file mode 100644
index 0000000..c9c9975
--- /dev/null
+++ b/src/main/java/org/apache/maven/report/projectinfo/avatars/AvatarsProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package org.apache.maven.report.projectinfo.avatars;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Avatar provider API.
+ */
+public interface AvatarsProvider {
+
+ /**
+ * Set a base URL for provider
+ *
+ * @param baseUrl for provider
+ */
+ void setBaseUrl(String baseUrl);
+
+ /**
+ * Set site output directory. Used to store avatar images in project.
+ *
+ * @param outputDirectory a site output directory
+ */
+ void setOutputDirectory(File outputDirectory);
+
+ /**
+ * Return a URL for avatar image.
+ *
+ * @param email email address for gravatar image
+ * @return a URL for avatar image
+ */
+ String getAvatarUrl(String email);
+
+ /**
+ * Return a local path to downloaded avatar image.
+ *
+ * @param email email address for gravatar image
+ * @return a local avatar path
+ * @throws IOException if problem with image downloading
+ */
+ String getLocalAvatarPath(String email) throws IOException;
+}
diff --git a/src/main/java/org/apache/maven/report/projectinfo/avatars/GravatarProvider.java b/src/main/java/org/apache/maven/report/projectinfo/avatars/GravatarProvider.java
new file mode 100644
index 0000000..d3b5405
--- /dev/null
+++ b/src/main/java/org/apache/maven/report/projectinfo/avatars/GravatarProvider.java
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+package org.apache.maven.report.projectinfo.avatars;
+
+import javax.inject.Named;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+
+import org.codehaus.plexus.util.IOUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provider for user avatar from gravatar.com
+ * <p>
+ * <a href="https://docs.gravatar.com/api/avatars/images/">Gravatar API</a>
+ */
+@Named("gravatar")
+class GravatarProvider implements AvatarsProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GravatarProvider.class);
+
+ private static final String AVATAR_SIZE = "s=60";
+
+ private static final String AVATAR_DIRECTORY = "avatars";
+
+ private static final String AVATAR_DEFAULT_FILE_NAME = "00000000000000000000000000000000.jpg";
+
+ private String baseUrl = "https://www.gravatar.com/avatar/";
+
+ private Path outputDirectory;
+
+ @Override
+ public void setBaseUrl(String baseUrl) {
+ this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
+ }
+
+ @Override
+ public void setOutputDirectory(File outputDirectory) {
+ this.outputDirectory = outputDirectory.toPath();
+ }
+
+ public String getAvatarUrl(String email) {
+ return getAvatarUrl(email, "blank");
+ }
+
+ private String getAvatarUrl(String email, String defaultAvatar) {
+ if (email == null || email.isEmpty()) {
+ return getSpacerGravatarUrl();
+ }
+
+ try {
+ email = email.trim().toLowerCase(Locale.ROOT);
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.update(email.getBytes());
+ byte[] byteData = md.digest();
+ StringBuilder sb = new StringBuilder();
+ final int lowerEightBitsOnly = 0xff;
+ for (byte aByteData : byteData) {
+ sb.append(Integer.toString((aByteData & lowerEightBitsOnly) + 0x100, 16)
+ .substring(1));
+ }
+ return baseUrl + sb + ".jpg?d=" + defaultAvatar + "&" + AVATAR_SIZE;
+ } catch (NoSuchAlgorithmException e) {
+ LOGGER.warn("Error while getting MD5 hash, use default image: {}", e.getMessage());
+ return getSpacerGravatarUrl();
+ }
+ }
+
+ @Override
+ public String getLocalAvatarPath(String email) throws IOException {
+ // use 404 http status for not existing avatars
+ String avatarUrl = getAvatarUrl(email, "404");
+ try {
+ URL url = new URI(avatarUrl).toURL();
+ Path name = Paths.get(url.getPath()).getFileName();
+ if (AVATAR_DEFAULT_FILE_NAME.equals(name.toString())) {
+ copyDefault();
+ } else {
+ copyUrl(url, outputDirectory.resolve(AVATAR_DIRECTORY).resolve(name));
+ }
+ return AVATAR_DIRECTORY + "/" + name;
+ } catch (URISyntaxException | IOException e) {
+ if (e instanceof FileNotFoundException) {
+ LOGGER.debug(
+ "Error while getting external avatar url for: {}, use default image: {}:{}",
+ email,
+ e.getClass().getName(),
+ e.getMessage());
+ } else {
+ LOGGER.warn(
+ "Error while getting external avatar url for: {}, use default image: {}:{}",
+ email,
+ e.getClass().getName(),
+ e.getMessage());
+ }
+ copyDefault();
+ return AVATAR_DIRECTORY + "/" + AVATAR_DEFAULT_FILE_NAME;
+ }
+ }
+
+ private String getSpacerGravatarUrl() {
+ return baseUrl + AVATAR_DEFAULT_FILE_NAME + "?d=blank&f=y&" + AVATAR_SIZE;
+ }
+
+ private void copyUrl(URL url, Path outputPath) throws IOException {
+ if (!Files.exists(outputPath)) {
+ Files.createDirectories(outputPath.getParent());
+ try (InputStream in = url.openStream();
+ OutputStream out = Files.newOutputStream(outputPath)) {
+ LOGGER.debug("Copying URL {} to {}", url, outputPath);
+ IOUtil.copy(in, out);
+ }
+ }
+ }
+
+ private void copyDefault() throws IOException {
+ Path outputPath = outputDirectory.resolve(AVATAR_DIRECTORY).resolve(AVATAR_DEFAULT_FILE_NAME);
+ if (!Files.exists(outputPath)) {
+ Files.createDirectories(outputPath.getParent());
+ try (InputStream in = getClass().getResourceAsStream("default-avatar.jpg");
+ OutputStream out = Files.newOutputStream(outputPath)) {
+ IOUtil.copy(in, out);
+ }
+ }
+ }
+}
diff --git a/src/main/resources/org/apache/maven/report/projectinfo/avatars/default-avatar.jpg b/src/main/resources/org/apache/maven/report/projectinfo/avatars/default-avatar.jpg
new file mode 100644
index 0000000..a32c67d
Binary files /dev/null and b/src/main/resources/org/apache/maven/report/projectinfo/avatars/default-avatar.jpg differ
diff --git a/src/test/java/org/apache/maven/report/projectinfo/TeamReportTest.java b/src/test/java/org/apache/maven/report/projectinfo/TeamReportTest.java
index e9d9340..409ea0d 100644
--- a/src/test/java/org/apache/maven/report/projectinfo/TeamReportTest.java
+++ b/src/test/java/org/apache/maven/report/projectinfo/TeamReportTest.java
@@ -50,6 +50,9 @@ public class TeamReportTest extends AbstractProjectInfoTestCase {
File pluginXmlFile = new File(getBasedir(), "src/test/resources/plugin-configs/" + "team-plugin-config.xml");
AbstractProjectInfoReport mojo = createReportMojo(getGoal(), pluginXmlFile);
setVariableValueToObject(mojo, "showAvatarImages", Boolean.TRUE);
+ setVariableValueToObject(mojo, "externalAvatarImages", Boolean.TRUE);
+ setVariableValueToObject(mojo, "avatarProviderName", "gravatar");
+ setVariableValueToObject(mojo, "avatarBaseUrl", "https://www.gravatar.com/avatar/");
generateReport(mojo, pluginXmlFile);
assertTrue("Test html generated", getGeneratedReport("team.html").exists());
diff --git a/src/test/java/org/apache/maven/report/projectinfo/avatars/GravatarProviderTest.java b/src/test/java/org/apache/maven/report/projectinfo/avatars/GravatarProviderTest.java
new file mode 100644
index 0000000..f3c91b4
--- /dev/null
+++ b/src/test/java/org/apache/maven/report/projectinfo/avatars/GravatarProviderTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+package org.apache.maven.report.projectinfo.avatars;
+
+import java.io.File;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class GravatarProviderTest {
+
+ @Rule
+ public TemporaryFolder tmpFolder = new TemporaryFolder();
+
+ @Test
+ public void urlShouldBeCorrect() {
+ GravatarProvider gravatarProvider = new GravatarProvider();
+ gravatarProvider.setBaseUrl("https://www.gravatar.com/avatar");
+ String externalAvatarUrl = gravatarProvider.getAvatarUrl("email@example.com");
+
+ assertEquals(
+ "https://www.gravatar.com/avatar/5658ffccee7f0ebfda2b226238b1eb6e.jpg?d=blank&s=60", externalAvatarUrl);
+ }
+
+ @Test
+ public void urlForEmptyEmailShouldBeCorrect() {
+ GravatarProvider gravatarProvider = new GravatarProvider();
+ gravatarProvider.setBaseUrl("https://www.gravatar.com/avatar");
+
+ String externalAvatarUrl = gravatarProvider.getAvatarUrl(null);
+
+ assertEquals(
+ "https://www.gravatar.com/avatar/00000000000000000000000000000000.jpg?d=blank&f=y&s=60",
+ externalAvatarUrl);
+
+ externalAvatarUrl = gravatarProvider.getAvatarUrl("");
+
+ assertEquals(
+ "https://www.gravatar.com/avatar/00000000000000000000000000000000.jpg?d=blank&f=y&s=60",
+ externalAvatarUrl);
+ }
+
+ @Test
+ public void localAvatarPathShouldBeCorrect() throws Exception {
+ GravatarProvider gravatarProvider = new GravatarProvider();
+ gravatarProvider.setBaseUrl("https://www.gravatar.com/avatar");
+ gravatarProvider.setOutputDirectory(tmpFolder.getRoot());
+ String localAvatarUrl = gravatarProvider.getLocalAvatarPath("sjaranowski@apache.org");
+ assertEquals("avatars/90cc13b765c79d2d55ca64388ea2bc5f.jpg", localAvatarUrl);
+ assertTrue(new File(tmpFolder.getRoot(), "avatars/90cc13b765c79d2d55ca64388ea2bc5f.jpg").exists());
+ }
+
+ @Test
+ public void localAvatarPathShouldHaveDefaultForNotExisting() throws Exception {
+ GravatarProvider gravatarProvider = new GravatarProvider();
+ gravatarProvider.setBaseUrl("https://www.gravatar.com/avatar");
+ gravatarProvider.setOutputDirectory(tmpFolder.getRoot());
+ String localAvatarUrl = gravatarProvider.getLocalAvatarPath("test@example.com");
+ assertEquals("avatars/00000000000000000000000000000000.jpg", localAvatarUrl);
+ assertTrue(new File(tmpFolder.getRoot(), "avatars/00000000000000000000000000000000.jpg").exists());
+ }
+
+ @Test
+ public void localAvatarPathShouldBeCorrectForDefault() throws Exception {
+ GravatarProvider gravatarProvider = new GravatarProvider();
+ gravatarProvider.setBaseUrl("https://www.gravatar.com/avatar");
+ gravatarProvider.setOutputDirectory(tmpFolder.getRoot());
+ String localAvatarUrl = gravatarProvider.getLocalAvatarPath(null);
+ assertEquals("avatars/00000000000000000000000000000000.jpg", localAvatarUrl);
+ assertTrue(new File(tmpFolder.getRoot(), "avatars/00000000000000000000000000000000.jpg").exists());
+ }
+}
diff --git a/src/test/java/org/apache/maven/report/projectinfo/stubs/TeamStub.java b/src/test/java/org/apache/maven/report/projectinfo/stubs/TeamStub.java
index 63d0e7b..bc41f1a 100644
--- a/src/test/java/org/apache/maven/report/projectinfo/stubs/TeamStub.java
+++ b/src/test/java/org/apache/maven/report/projectinfo/stubs/TeamStub.java
@@ -18,6 +18,11 @@
*/
package org.apache.maven.report.projectinfo.stubs;
+import java.util.List;
+
+import org.apache.maven.model.Contributor;
+import org.apache.maven.model.Developer;
+
/**
* @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
* @version $Id$
@@ -27,4 +32,14 @@ public class TeamStub extends ProjectInfoProjectStub {
protected String getPOM() {
return "team-plugin-config.xml";
}
+
+ @Override
+ public List<Contributor> getContributors() {
+ return getModel().getContributors();
+ }
+
+ @Override
+ public List<Developer> getDevelopers() {
+ return getModel().getDevelopers();
+ }
}