Skip to content

Commit

Permalink
Merge pull request #17 from TechnologyBrewery/16-fix-forked-manual-ac…
Browse files Browse the repository at this point in the history
…tions

#16: 🐛 fix forked session issues with manual action notifications…
  • Loading branch information
d-ryan-ashcraft authored Jun 21, 2023
2 parents 1bcc806 + 8d8e980 commit 32c1ec7
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.technologybrewery.fermenter.mda.metamodel.ModelInstanceRepository;
import org.technologybrewery.fermenter.mda.metamodel.ModelInstanceUrl;
import org.technologybrewery.fermenter.mda.metamodel.ModelRepositoryConfiguration;
import org.technologybrewery.fermenter.mda.notification.NotificationCollector;
import org.technologybrewery.fermenter.mda.notification.NotificationService;
import org.technologybrewery.fermenter.mda.reporting.StatisticsService;
import org.technologybrewery.fermenter.mda.util.MessageTracker;
Expand Down Expand Up @@ -189,10 +188,9 @@ public void execute() throws MojoExecutionException {

}

// move notifications to the session between plugin invocations so they can be output
// store notifications in the target directory between plugin invocations so they can be output
// at the end of the build:
notificationService.mergeNotificationsIntoSessionForCrossProjectStorage();
NotificationCollector.cleanup();
notificationService.recordNotifications();

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public final class NotificationCollector {
private static final ThreadLocal<Map<String, Map<String, Notification>>> NOTIFICATIONS = ThreadLocal.withInitial(ConcurrentHashMap::new);

private NotificationCollector() {
// prevent private instationation of all static class
// prevent private instantiation of all static class
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package org.technologybrewery.fermenter.mda.notification;

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.technologybrewery.fermenter.mda.generator.GenerationException;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
* Listens for the end of the Maven Session and then outputs any accumulated manual action notifications.
Expand All @@ -21,7 +31,7 @@
public class NotificationService extends AbstractMavenLifecycleParticipant {

private static final Logger logger = LoggerFactory.getLogger(NotificationService.class);
private static final String NOTIFICATIONS = "notifications";
private static final String NOTIFICATION_DIRECTORY_PATH = "target/manual-action-notifications/";

private MavenSession session;

Expand Down Expand Up @@ -51,7 +61,11 @@ public void afterSessionEnd(MavenSession session) {
this.hideManualActions = Boolean.parseBoolean(rawHideManualActions);
}

displayNotifications();
try {
displayNotifications();
} catch (IOException e) {
throw new GenerationException("Could not emit manual action notifications! Check target directories for more details.", e);
}
}

static void addNotificationToPassedMap(String targetFile, Notification notification, Map<String, Map<String,
Expand All @@ -69,56 +83,58 @@ static void addNotificationToPassedMap(String targetFile, Notification notificat
}

/**
* Merges any notifications from the current plugin execution into the session for storage across plugin invocations.
* Writes any encountered notifications to a file for use later. These are written to the path defined by
* NOTIFICATION_DIRECTORY_PATH.
*/
public synchronized void mergeNotificationsIntoSessionForCrossProjectStorage() {
public void recordNotifications() {
int manualActionCount = 0;
File projectParentFile = new File(NOTIFICATION_DIRECTORY_PATH);
Map<String, Map<String, Notification>> collectorNotifications = NotificationCollector.getNotifications();
Map<String, Map<String, Notification>> sessionNotifications = getNotificationsFromSession();

synchronized (this) {
if (sessionNotifications == null) {
sessionNotifications = collectorNotifications;
Properties userProperties = session.getUserProperties();
userProperties.put(NOTIFICATIONS, sessionNotifications);
} else {
for (Map.Entry<String, Map<String, Notification>> entry : collectorNotifications.entrySet()) {
String fileName = entry.getKey();
Map<String, Notification> notificationsForFile = entry.getValue();
for (Map.Entry<String, Notification> subMapEntry : notificationsForFile.entrySet()) {
addNotificationToPassedMap(fileName, subMapEntry.getValue(), sessionNotifications);
}
for (Map.Entry<String, Map<String, Notification>> entry : collectorNotifications.entrySet()) {
String fileName = entry.getKey();
Map<String, Notification> notificationsForFile = entry.getValue();
int i = 0;
for (Map.Entry<String, Notification> subMapEntry : notificationsForFile.entrySet()) {
File outputFile = new File(projectParentFile, FilenameUtils.getName(fileName + "-" + i++ + ".txt"));
try {
FileUtils.forceMkdir(projectParentFile);
FileUtils.write(outputFile, subMapEntry.getValue().getNotificationAsString(), Charset.defaultCharset());
manualActionCount++;
} catch (IOException e) {
throw new GenerationException("Could not write manual action notification to disk!", e);
}
}

if (manualActionCount > 0) {
logger.warn("{} manual action notification encountered - details written to {}", manualActionCount,
projectParentFile.getAbsoluteFile());
}

}
}

private Map<String, Map<String, Notification>> getNotificationsFromSession() {
Properties userProperties = session.getUserProperties();
@SuppressWarnings("unchecked")
Map<String, Map<String, Notification>> stringMapMap = (Map<String, Map<String, Notification>>) userProperties.get(NOTIFICATIONS);
return stringMapMap;
NotificationCollector.cleanup();
}

void displayNotifications() {
private void displayNotifications() throws IOException {
if (this.hideManualActions) {
logger.debug("Hiding manual actions");

} else if (logger.isWarnEnabled()) {
// Get all notifications, then display them by file being modified
Map<String, Map<String, Notification>> sessionNotifications = getNotificationsFromSession();
Map<String, List<File>> notificationMap = findNotificationForDisplay();

if (MapUtils.isNotEmpty(sessionNotifications)) {
if (MapUtils.isNotEmpty(notificationMap)) {
int i = 1;
logger.warn("Manual action steps were detected by fermenter-mda in {} place(s)", sessionNotifications.size());
logger.warn("Manual action steps were detected by fermenter-mda in {} module(s)", notificationMap.size());
logger.warn("");
for (Map.Entry<String, Map<String, Notification>> entry : sessionNotifications.entrySet()) {
logger.debug("Notifications for: {}", entry.getKey());
for (Map.Entry<String, List<File>> entry : notificationMap.entrySet()) {
logger.debug("Notifications for artifactId: {}", entry.getKey());

for (Object notification : entry.getValue().values()) {
for (File notification : entry.getValue()) {
logger.warn("------------------------------------------------------------------------");
logger.warn("Manual Action #{}", i++);
logger.warn("------------------------------------------------------------------------");
logger.warn(notification.toString());
logger.warn(FileUtils.readFileToString(notification, Charset.defaultCharset()));
}
}

Expand All @@ -128,4 +144,22 @@ void displayNotifications() {
}
}

private Map<String, List<File>> findNotificationForDisplay() {
Map<String, List<File>> resultMap = new HashMap<>();
List<MavenProject> projects = this.session.getAllProjects();
for (MavenProject project : projects) {
File projectBaseDirectory = project.getBasedir();
File projectNotificationDirectory = new File(projectBaseDirectory, NOTIFICATION_DIRECTORY_PATH);
if (projectNotificationDirectory.exists()) {
File[] fileArray = projectNotificationDirectory.listFiles();
if (fileArray != null) {
resultMap.put(project.getArtifactId(), Arrays.stream(fileArray).collect(Collectors.toList()));
}
}
}

return resultMap;

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ Feature: Support the ability to create notifications that can be output at the e
| key | items |
| you've-got-to-hide-your-love-away | lennon |
| you-won't-see-me | mccartney |

@manual
Scenario: Collect per-project written manual action notifications and emit them at the end of the build
Given one or more Maven modules that create manual action notifications in their "target/manual-action-notifications" folder
When the end of the Maven build is reached
Then the notifications for the Maven modules that were part of the build are emitted to the console

0 comments on commit 32c1ec7

Please sign in to comment.