Added events to store information about passing tasks

This commit is contained in:
Marcin Grzejszczak
2019-01-04 13:21:42 +01:00
parent bd9e9afe7f
commit b6c3888bc8
48 changed files with 422 additions and 173 deletions

View File

@@ -4,16 +4,18 @@ import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.docs.DocumentationUpdater;
import org.springframework.cloud.release.internal.gradle.GradleUpdater;
import org.springframework.cloud.release.internal.post.PostReleaseActions;
import org.springframework.cloud.release.internal.sagan.SaganUpdater;
import org.springframework.cloud.release.internal.template.TemplateGenerator;
import org.springframework.cloud.release.internal.git.ProjectGitHandler;
import org.springframework.cloud.release.internal.gradle.GradleUpdater;
import org.springframework.cloud.release.internal.pom.ProjectPomUpdater;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.cloud.release.internal.pom.Projects;
import org.springframework.cloud.release.internal.post.PostReleaseActions;
import org.springframework.cloud.release.internal.project.ProjectBuilder;
import org.springframework.cloud.release.internal.sagan.SaganUpdater;
import org.springframework.cloud.release.internal.tech.MakeBuildUnstableException;
import org.springframework.cloud.release.internal.template.TemplateGenerator;
import org.springframework.util.Assert;
/**
@@ -199,6 +201,7 @@ public class Releaser {
log.info("\nSuccessfully updated Sagan for branch [{}]", currentBranch);
} catch (Exception ex) {
log.error("\n\n[BUILD UNSTABLE] WARNING! FAILED TO UPDATE SAGAN, DUE TO THE FOLLOWING EXCEPTION", ex);
throw new MakeBuildUnstableException(ex);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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 org.springframework.cloud.release.internal.tech;
/**
* Exception to be thrown if one wants to continue with the build
* and throw this exception at the end of the release
*/
public class MakeBuildUnstableException extends RuntimeException {
public MakeBuildUnstableException(Throwable cause) {
super(cause);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -2,7 +2,7 @@
<!--
Copyright 2013-2017 the original author or authors.
Copyright 2013-2019 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@@ -2,15 +2,22 @@ package org.springframework.cloud.release.internal.spring;
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.Releaser;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.cloud.release.internal.pom.Projects;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
/**
* @author Marcin Grzejszczak
*/
class Args {
private static final Logger log = LoggerFactory.getLogger(Args.class);
final Releaser releaser;
final File project;
final Projects projects;
@@ -19,10 +26,11 @@ class Args {
final ReleaserProperties properties;
final boolean interactive;
final TaskType taskType;
final ApplicationEventPublisher applicationEventPublisher;
Args(Releaser releaser, File project, Projects projects, ProjectVersion originalVersion,
ProjectVersion versionFromScRelease, ReleaserProperties properties,
boolean interactive, TaskType taskType) {
boolean interactive, TaskType taskType, ApplicationEventPublisher applicationEventPublisher) {
this.releaser = releaser;
this.project = project;
this.projects = projects;
@@ -31,13 +39,14 @@ class Args {
this.properties = properties;
this.interactive = interactive;
this.taskType = taskType;
this.applicationEventPublisher = applicationEventPublisher;
}
// Used by meta-release task
Args(Releaser releaser, Projects projects,
ProjectVersion versionFromScRelease,
ReleaserProperties properties,
boolean interactive) {
boolean interactive, ApplicationEventPublisher applicationEventPublisher) {
this.releaser = releaser;
this.project = null;
this.projects = projects;
@@ -46,6 +55,7 @@ class Args {
this.properties = properties;
this.interactive = interactive;
this.taskType = TaskType.POST_RELEASE;
this.applicationEventPublisher = applicationEventPublisher;
}
// Used for tests
@@ -58,6 +68,19 @@ class Args {
this.properties = null;
this.interactive = false;
this.taskType = taskType;
this.applicationEventPublisher = null;
}
String projectName() {
return this.project != null ? this.project.getName() : "";
}
void publishEvent(ApplicationEvent applicationEvent) {
if (this.applicationEventPublisher == null) {
log.warn("Application Event Publisher not present");
return;
}
this.applicationEventPublisher.publishEvent(applicationEvent);
}
@Override

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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 org.springframework.cloud.release.internal.spring;
import org.springframework.context.ApplicationEvent;
class BuildCompleted extends ApplicationEvent {
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
BuildCompleted(Object source) {
super(source);
}
}

View File

@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.Releaser;
import org.springframework.cloud.release.internal.ReleaserProperties;
import org.springframework.cloud.release.internal.options.Options;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.StringUtils;
/**
@@ -20,15 +21,24 @@ class OptionsProcessor {
private final Releaser releaser;
private final ReleaserProperties properties;
private final List<Task> allTasks;
private final ApplicationEventPublisher applicationEventPublisher;
OptionsProcessor(Releaser releaser, ReleaserProperties properties) {
this(releaser, properties, Tasks.ALL_TASKS_PER_PROJECT);
OptionsProcessor(Releaser releaser, ReleaserProperties properties, ApplicationEventPublisher applicationEventPublisher) {
this(releaser, properties, applicationEventPublisher, Tasks.ALL_TASKS_PER_PROJECT);
}
OptionsProcessor(Releaser releaser, ReleaserProperties properties, ApplicationEventPublisher applicationEventPublisher, List<Task> allTasks) {
this.releaser = releaser;
this.properties = properties;
this.allTasks = allTasks;
this.applicationEventPublisher = applicationEventPublisher;
}
OptionsProcessor(Releaser releaser, ReleaserProperties properties, List<Task> allTasks) {
this.releaser = releaser;
this.properties = properties;
this.allTasks = allTasks;
this.applicationEventPublisher = null;
}
void processOptions(Options options, Args defaultArgs) {
@@ -191,7 +201,7 @@ class OptionsProcessor {
List<String> tasksFromInput = Arrays.asList(input.split(","));
List<String> taskNames = new ArrayList<>();
for (String task : tasksFromInput) {
Integer taskIndex = Integer.valueOf(task);
int taskIndex = Integer.parseInt(task);
taskNames.add(tasks.get(taskIndex).name);
}
tasks(tasks, taskNames, defaultArgs);
@@ -212,7 +222,7 @@ class OptionsProcessor {
private Args args(Args defaultArgs, boolean interactive) {
return new Args(this.releaser, defaultArgs.project, defaultArgs.projects,
defaultArgs.originalVersion, defaultArgs.versionFromScRelease,
this.properties, interactive, defaultArgs.taskType);
this.properties, interactive, defaultArgs.taskType, this.applicationEventPublisher);
}
String chosenOption() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2017 the original author or authors.
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import org.springframework.cloud.release.internal.sagan.SaganClient;
import org.springframework.cloud.release.internal.sagan.SaganUpdater;
import org.springframework.cloud.release.internal.template.TemplateGenerator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -40,10 +41,16 @@ class ReleaserConfiguration {
@Autowired
ReleaserProperties properties;
@Bean
TaskCollector taskCollector() {
return new TaskCollector();
}
@Bean
SpringReleaser springReleaser(Releaser releaser,
ReleaserPropertiesUpdater updater) {
return new SpringReleaser(releaser, this.properties, updater);
ReleaserPropertiesUpdater updater,
ApplicationEventPublisher applicationEventPublisher) {
return new SpringReleaser(releaser, this.properties, updater, applicationEventPublisher);
}
@Bean

View File

@@ -14,6 +14,7 @@ import org.springframework.cloud.release.internal.options.Options;
import org.springframework.cloud.release.internal.options.OptionsBuilder;
import org.springframework.cloud.release.internal.pom.ProjectVersion;
import org.springframework.cloud.release.internal.pom.Projects;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.StringUtils;
/**
@@ -28,21 +29,25 @@ public class SpringReleaser {
private final ReleaserProperties properties;
private final OptionsProcessor optionsProcessor;
private final ReleaserPropertiesUpdater updater;
private final ApplicationEventPublisher applicationEventPublisher;
public SpringReleaser(Releaser releaser, ReleaserProperties properties,
ReleaserPropertiesUpdater updater) {
ReleaserPropertiesUpdater updater, ApplicationEventPublisher applicationEventPublisher) {
this.releaser = releaser;
this.properties = properties;
this.updater = updater;
this.optionsProcessor = new OptionsProcessor(releaser, properties);
this.applicationEventPublisher = applicationEventPublisher;
this.optionsProcessor = new OptionsProcessor(releaser, properties, applicationEventPublisher);
}
SpringReleaser(Releaser releaser, ReleaserProperties properties,
OptionsProcessor optionsProcessor, ReleaserPropertiesUpdater updater) {
OptionsProcessor optionsProcessor, ReleaserPropertiesUpdater updater,
ApplicationEventPublisher applicationEventPublisher) {
this.releaser = releaser;
this.properties = properties;
this.optionsProcessor = optionsProcessor;
this.updater = updater;
this.applicationEventPublisher = applicationEventPublisher;
}
/**
@@ -60,9 +65,15 @@ public class SpringReleaser {
if (this.properties.isPostReleaseTasksOnly()) {
log.info("Skipping release process and moving only to post release");
this.optionsProcessor.postReleaseOptions(options, postReleaseOptionsAgs(options, projectsAndVersion));
buildCompleted();
return;
}
performReleaseAndPostRelease(options, projectsAndVersion);
buildCompleted();
}
private void buildCompleted() {
this.applicationEventPublisher.publishEvent(new BuildCompleted(this));
}
private void performReleaseAndPostRelease(Options options, ProjectsAndVersion projectsAndVersion) {
@@ -152,7 +163,7 @@ public class SpringReleaser {
this.properties.getPom().setBranch(version.version);
}
return new Args(this.releaser, projects, version,
this.properties, options.interactive);
this.properties, options.interactive, this.applicationEventPublisher);
}
private ProjectVersion versionFromBranch() {
@@ -201,7 +212,7 @@ public class SpringReleaser {
ProjectVersion originalVersion = new ProjectVersion(project);
final Args defaultArgs = new Args(this.releaser, project, projectsAndVersion.projectVersions,
originalVersion, projectsAndVersion.versionFromScRelease, this.properties,
options.interactive, taskType);
options.interactive, taskType, this.applicationEventPublisher);
log.debug("Processing project [{}] with args [{}]", project, defaultArgs);
this.optionsProcessor.processOptions(options, defaultArgs);
return projectsAndVersion;

View File

@@ -5,6 +5,8 @@ import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.release.internal.tech.MakeBuildUnstableException;
/**
* @author Marcin Grzejszczak
*/
@@ -38,6 +40,13 @@ class Task {
}
TaskAndException execute(Args args) {
TaskAndException taskAndException = doExecute(args);
args.publishEvent(new TaskCompleted(this,
args.projectName(), taskAndException));
return taskAndException;
}
private TaskAndException doExecute(Args args) {
if (args.taskType != this.taskType) {
log.info("Skipping [{}] since task type is [{}] and should be [{}]]",
this.name, this.taskType, args.taskType);
@@ -55,10 +64,13 @@ class Task {
} else {
return runTask(args);
}
} catch (Exception e) {
log.error("\n\n\nBUILD FAILED!!!\n\nException occurred for project <" +
(args.project != null ? args.project.getName() : "") + "> task <" +
this.name + "> \n\nwith description <" + this.description + ">\n\n", e);
}
catch (MakeBuildUnstableException atTheEnd) {
logError("TASK FAILED - WILL MARK THE BUILD UNSTABLE AT THE END!!!", args, atTheEnd);
return TaskAndException.failure(this, atTheEnd);
}
catch (Exception e) {
logError("BUILD FAILED!!!", args, e);
if (this.taskType == TaskType.RELEASE) {
throw e;
}
@@ -66,6 +78,12 @@ class Task {
}
}
private void logError(String prefix, Args args, Exception e) {
log.error("\n\n\n" + prefix + "\n\nException occurred for project <" +
(args.project != null ? args.project.getName() : "") + "> task <" +
this.name + "> \n\nwith description <" + this.description + ">\n\n", e);
}
private TaskAndException runTask(Args args) {
this.consumer.accept(args);
return TaskAndException.success(this);

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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 org.springframework.cloud.release.internal.spring;
import java.util.Arrays;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.stream.Collectors;
import com.jakewharton.fliptables.FlipTableConverters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.util.StringUtils;
class TaskCollector {
private static final Logger log = LoggerFactory.getLogger(TaskCollector.class);
private final Queue<TaskCompleted> completedTasks = new ArrayBlockingQueue<>(300);
@EventListener
public void handleTaskCompleted(TaskCompleted taskCompleted) {
this.completedTasks.add(taskCompleted);
log.info("Completed task: " + taskCompleted);
}
@EventListener
public void handleBuildCompleted(BuildCompleted buildCompleted) {
log.info("Build has finished. Will summarize the results");
List<Table> table = this.completedTasks.stream()
.map(task -> new Table(task.projectName, task.taskAndException))
.collect(Collectors.toList());
String string = "\n\n***** BUILD REPORT *****\n\n"
+ FlipTableConverters.fromIterable(table, Table.class)
+ "\n\n***** BUILD REPORT *****\n\n";
List<Table> brokenTasks = table.stream()
.filter(table1 -> StringUtils.hasText(table1.thrownException))
.collect(Collectors.toList());
if (!brokenTasks.isEmpty()) {
String brokenBuilds = "\n\n[BUILD UNSTABLE] The following release tasks are failing!\n\n" +
brokenTasks.stream()
.map(table1 ->
String.format("***** Project / Task : <%s/%s> ***** \nTask Description <%s>\nException Stacktrace \n\n%s",
table1.projectName, table1.taskCaption,
table1.taskDescription, Arrays
.stream(table1.exception.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"))))
.collect(Collectors.joining("\n\n"));
log.warn(string + brokenBuilds);
this.completedTasks.clear();
throw new IllegalStateException(brokenBuilds);
} else {
log.info(string);
this.completedTasks.clear();
}
}
}
class Table {
final String projectName;
final String taskCaption;
final String taskDescription;
final String taskState;
final String thrownException;
Exception exception;
Table(String projectName, TaskAndException tae) {
this.projectName = projectName;
this.taskCaption = tae.task.name;
this.taskDescription = tae.task.description;
this.taskState = tae.taskState.name().toLowerCase();
this.thrownException = tae.exception == null ? "" :
NestedExceptionUtils.getMostSpecificCause(tae.exception).toString();
this.exception = tae.exception;
}
public String getProjectName() {
return this.projectName;
}
public String getTaskCaption() {
return this.taskCaption;
}
public String getTaskDescription() {
return this.taskDescription;
}
public String getTaskState() {
return this.taskState;
}
public String getThrownException() {
return this.thrownException;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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 org.springframework.cloud.release.internal.spring;
import org.springframework.context.ApplicationEvent;
class TaskCompleted extends ApplicationEvent {
final String projectName;
final TaskAndException taskAndException;
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
TaskCompleted(Object source, String projectName, TaskAndException taskAndException) {
super(source);
this.taskAndException = taskAndException;
this.projectName = projectName;
}
@Override
public String toString() {
return "TaskCompleted{" +
"projectName='" + this.projectName + '\'' +
", taskName=" + this.taskAndException.task.name +
'}';
}
}

View File

@@ -1,19 +1,11 @@
package org.springframework.cloud.release.internal.spring;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.jakewharton.fliptables.FlipTableConverters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.util.StringUtils;
/**
* All tasks that can be executed by the releaser
*
@@ -198,8 +190,6 @@ enum TaskType {
class CompositeConsumer implements Consumer<Args> {
private static final Logger log = LoggerFactory.getLogger(CompositeConsumer.class);
private final List<Task> tasks;
private final Consumer<Args> setup;
@@ -216,64 +206,7 @@ class CompositeConsumer implements Consumer<Args> {
@Override
public void accept(Args args) {
this.setup.accept(args);
List<Table> table = this.tasks.stream()
.map(task -> new Table(task.execute(args)))
.collect(Collectors.toList());
String string = "\n\n***** BUILD REPORT *****\n\n"
+ FlipTableConverters.fromIterable(table, Table.class)
+ "\n\n***** BUILD REPORT *****\n\n";
List<Table> brokenTasks = table.stream()
.filter(table1 -> StringUtils.hasText(table1.thrownException))
.collect(Collectors.toList());
if (!brokenTasks.isEmpty()) {
String brokenBuilds = "\n\n[BUILD UNSTABLE] The following post release tasks are failing!\n\n" +
brokenTasks.stream()
.map(table1 ->
String.format("***** Task Caption: <%s> ***** \nTask Description <%s>\nException Stacktrace \n\n%s",
table1.taskCaption, table1.taskDescription, Arrays
.stream(table1.exception.getStackTrace())
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"))))
.collect(Collectors.joining("\n\n"));
log.warn(string + brokenBuilds);
throw new IllegalStateException(brokenBuilds);
} else {
log.info(string);
}
this.tasks.forEach(task -> task.execute(args));
}
}
class Table {
final String taskCaption;
final String taskDescription;
final String taskState;
final String thrownException;
Exception exception;
Table(TaskAndException tae) {
this.taskCaption = tae.task.name;
this.taskDescription = tae.task.description;
this.taskState = tae.taskState.name().toLowerCase();
this.thrownException = tae.exception == null ? "" :
NestedExceptionUtils.getMostSpecificCause(tae.exception).toString();
this.exception = tae.exception;
}
public String getTaskCaption() {
return this.taskCaption;
}
public String getTaskDescription() {
return this.taskDescription;
}
public String getTaskState() {
return this.taskState;
}
public String getThrownException() {
return this.thrownException;
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright 2013-2017 the original author or authors.
*
* 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 org.springframework.cloud.release.internal;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ReleaserApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@@ -49,6 +49,7 @@ import org.springframework.cloud.release.internal.sagan.SaganClient;
import org.springframework.cloud.release.internal.sagan.SaganUpdater;
import org.springframework.cloud.release.internal.template.TemplateGenerator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.FileSystemUtils;
import static org.assertj.core.api.BDDAssertions.then;
@@ -76,6 +77,7 @@ public class AcceptanceTests {
ApplicationContext applicationContext = Mockito.mock(ApplicationContext.class);
ReleaserPropertiesUpdater updater = new ReleaserPropertiesUpdater(this.applicationContext);
PostReleaseActions postReleaseActions = Mockito.mock(PostReleaseActions.class);
ApplicationEventPublisher applicationEventPublisher = Mockito.mock(ApplicationEventPublisher.class);
@Before
public void setup() throws Exception {
@@ -572,7 +574,7 @@ public class AcceptanceTests {
private SpringReleaser releaserWithFullDeployment(String expectedVersion,
String projectName, ReleaserProperties properties) throws Exception {
Releaser releaser = defaultReleaser(expectedVersion, projectName, properties);
return new SpringReleaser(releaser, properties, new OptionsProcessor(releaser, properties) {
return new SpringReleaser(releaser, properties, new OptionsProcessor(releaser, properties, this.applicationEventPublisher) {
@Override String chosenOption() {
return "0";
}
@@ -581,12 +583,12 @@ public class AcceptanceTests {
options.interactive = false;
super.postReleaseOptions(options, defaultArgs);
}
}, this.updater);
}, this.updater, this.applicationEventPublisher);
}
private SpringReleaser metaReleaserWithFullDeployment(ReleaserProperties properties) throws Exception {
Releaser releaser = defaultMetaReleaser(properties);
return new SpringReleaser(releaser, properties, new OptionsProcessor(releaser, properties) {
return new SpringReleaser(releaser, properties, new OptionsProcessor(releaser, properties, this.applicationEventPublisher) {
@Override String chosenOption() {
return "0";
}
@@ -595,7 +597,7 @@ public class AcceptanceTests {
options.interactive = false;
super.postReleaseOptions(options, defaultArgs);
}
}, this.updater);
}, this.updater, this.applicationEventPublisher);
}
private SpringReleaser releaserWithSnapshotScRelease(File projectFile, String projectName,
@@ -607,7 +609,7 @@ public class AcceptanceTests {
private SpringReleaser templateOnlyReleaser(File projectFile, String projectName, String branch, String expectedVersion) throws Exception {
ReleaserProperties properties = releaserProperties(projectFile, branch);
Releaser releaser = defaultReleaser(expectedVersion, projectName, properties);
return new SpringReleaser(releaser, properties, new OptionsProcessor(releaser, properties) {
return new SpringReleaser(releaser, properties, new OptionsProcessor(releaser, properties, this.applicationEventPublisher) {
@Override String chosenOption() {
return "13";
}
@@ -616,7 +618,7 @@ public class AcceptanceTests {
options.interactive = true;
super.postReleaseOptions(options, defaultArgs);
}
}, this.updater);
}, this.updater, this.applicationEventPublisher);
}
private Releaser defaultReleaser(String expectedVersion, String projectName,

View File

@@ -39,22 +39,6 @@ public class CompositeConsumerTests {
compositeConsumer.accept(new Args(TaskType.RELEASE)))
.isInstanceOf(MyException.class);
}
@Test
public void should_throw_exception_for_a_post_release_task_after_creating_a_report() {
CompositeConsumer compositeConsumer = new CompositeConsumer(Arrays.asList(
new Task("foo", "foo", "foo", "foo",
(args -> {}), TaskType.POST_RELEASE),
new Task("bar", "bar", "bar", "bar",
(args -> { throw new MyException(); }), TaskType.POST_RELEASE),
new Task("baz", "baz", "baz", "baz",
(args -> { throw new MyException(); }), TaskType.POST_RELEASE)
));
BDDAssertions.thenThrownBy(() ->
compositeConsumer.accept(new Args(TaskType.POST_RELEASE)))
.isInstanceOf(IllegalStateException.class);
}
}
class MyException extends RuntimeException {}

View File

@@ -272,7 +272,7 @@ public class OptionsProcessorTests {
}
private Args args() {
return new Args(null, null, null, null, null, null, false, TaskType.RELEASE);
return new Args(null, null, null, null, null, null, false, TaskType.RELEASE, null);
}
private List<String> list(String... list) {

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* 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 org.springframework.cloud.release.internal.spring;
import org.assertj.core.api.BDDAssertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ReleaserApplicationEventTests.Config.class,
properties = "releaser.git.oauth-token=some-fake-token")
public class ReleaserApplicationEventTests {
@Autowired
ApplicationEventPublisher publisher;
@Test
public void should_throw_exceptions_when_at_least_one_task_is_failing() {
this.publisher.publishEvent(new TaskCompleted(this, "foo", TaskAndException.skipped(Tasks.PUSH)));
this.publisher.publishEvent(new TaskCompleted(this, "foo", TaskAndException.success(Tasks.CLOSE_MILESTONE)));
this.publisher.publishEvent(new TaskCompleted(this, "foo", TaskAndException.failure(Tasks.DEPLOY, new RuntimeException("boom!"))));
BDDAssertions.thenThrownBy(() -> {
this.publisher.publishEvent(new BuildCompleted(this));
}).hasMessageContaining("[BUILD UNSTABLE] The following");
}
@Test
public void should_not_fail_when_all_tasks_not_failing() {
this.publisher.publishEvent(new TaskCompleted(this, "foo", TaskAndException.skipped(Tasks.PUSH)));
this.publisher.publishEvent(new TaskCompleted(this, "foo", TaskAndException.success(Tasks.CLOSE_MILESTONE)));
this.publisher.publishEvent(new BuildCompleted(this));
}
@Configuration
@EnableAutoConfiguration
@ComponentScan({
"org.springframework.cloud.release.internal.options",
"org.springframework.cloud.release.internal.sagan",
"org.springframework.cloud.release.internal.spring",
})
static class Config {
}
}

View File

@@ -25,6 +25,7 @@ import org.springframework.cloud.release.internal.ReleaserPropertiesAware;
import org.springframework.cloud.release.internal.options.Options;
import org.springframework.cloud.release.internal.options.OptionsBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
/**
* @author Marcin Grzejszczak
@@ -41,6 +42,7 @@ public class SpringReleaserTests {
Aware1 aware1 = new Aware1();
Aware2 aware2 = new Aware2();
ReleaserPropertiesUpdater updater;
@Mock ApplicationEventPublisher applicationEventPublisher;
File releaserUpdater = new File(ReleaserPropertiesUpdaterTests.class
.getResource("/projects/releaser-updater/config/releaser.yml").toURI());
@@ -113,7 +115,7 @@ public class SpringReleaserTests {
private SpringReleaser stubbedSpringReleaser() {
return new SpringReleaser(this.releaser, this.properties,
this.optionsProcessor, this.updater) {
this.optionsProcessor, this.updater, applicationEventPublisher) {
@Override
Args postReleaseOptionsAgs(Options options, ProjectsAndVersion projectsAndVersion) {