Skip to content

Commit

Permalink
(cake-buildGH-2661) Support async implementations of error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
GeertvanHorrik committed Nov 20, 2019
1 parent 7494c7e commit 878aab8
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 25 deletions.
14 changes: 7 additions & 7 deletions src/Cake.Core/CakeEngine.cs
Expand Up @@ -344,13 +344,13 @@ private static bool ShouldTaskExecute(ICakeContext context, CakeTask task, CakeT
// Got an error reporter?
if (task.ErrorReporter != null)
{
ReportErrors(strategy, task.ErrorReporter, exception);
await ReportErrorsAsync(strategy, task.ErrorReporter, exception);
}

// Got an error handler?
if (task.ErrorHandler != null)
{
HandleErrors(strategy, task.ErrorHandler, exception, context);
await HandleErrorsAsync(strategy, task.ErrorHandler, exception, context);
}
else
{
Expand All @@ -363,7 +363,7 @@ private static bool ShouldTaskExecute(ICakeContext context, CakeTask task, CakeT
{
if (task.FinallyHandler != null)
{
strategy.InvokeFinally(task.FinallyHandler);
await strategy.InvokeFinallyAsync(task.FinallyHandler);
}

PerformTaskTeardown(context, strategy, task, stopWatch.Elapsed, false, taskException);
Expand Down Expand Up @@ -442,12 +442,12 @@ private static bool IsDelegatedTask(CakeTask task)
return task != null && !task.Actions.Any();
}

private static void ReportErrors(IExecutionStrategy strategy, Action<Exception> errorReporter,
private static async Task ReportErrorsAsync(IExecutionStrategy strategy, Func<Exception, Task> errorReporter,
Exception taskException)
{
try
{
strategy.ReportErrors(errorReporter, taskException);
await strategy.ReportErrorsAsync(errorReporter, taskException);
}
// ReSharper disable once EmptyGeneralCatchClause
catch
Expand All @@ -456,11 +456,11 @@ private static bool IsDelegatedTask(CakeTask task)
}
}

private void HandleErrors(IExecutionStrategy strategy, Action<Exception, ICakeContext> errorHandler, Exception exception, ICakeContext context)
private async Task HandleErrorsAsync(IExecutionStrategy strategy, Func<Exception, ICakeContext, Task> errorHandler, Exception exception, ICakeContext context)
{
try
{
strategy.HandleErrors(errorHandler, exception, context);
await strategy.HandleErrorsAsync(errorHandler, exception, context);
}
catch (Exception errorHandlerException)
{
Expand Down
6 changes: 3 additions & 3 deletions src/Cake.Core/CakeTask.cs
Expand Up @@ -48,17 +48,17 @@ public sealed class CakeTask : ICakeTaskInfo
/// Gets or sets the error handler.
/// </summary>
/// <value>The error handler.</value>
public Action<Exception, ICakeContext> ErrorHandler { get; set; }
public Func<Exception, ICakeContext, Task> ErrorHandler { get; set; }

/// <summary>
/// Gets or sets the error reporter.
/// </summary>
public Action<Exception> ErrorReporter { get; set; }
public Func<Exception, Task> ErrorReporter { get; set; }

/// <summary>
/// Gets or sets the finally handler.
/// </summary>
public Action FinallyHandler { get; set; }
public Func<Task> FinallyHandler { get; set; }

/// <summary>
/// Gets the task's actions.
Expand Down
126 changes: 126 additions & 0 deletions src/Cake.Core/CakeTaskBuilder.Errors.cs
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Threading.Tasks;

namespace Cake.Core
{
Expand Down Expand Up @@ -45,6 +46,22 @@ public static CakeTaskBuilder OnError(this CakeTaskBuilder builder, Action error
return OnError(builder, exception => errorHandler());
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="errorHandler">The error handler.</param>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder OnError(this CakeTaskBuilder builder, Func<Task> errorHandler)
{
if (errorHandler == null)
{
throw new ArgumentNullException(nameof(errorHandler));
}

return OnError(builder, async exception => await errorHandler());
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
Expand All @@ -56,6 +73,22 @@ public static CakeTaskBuilder OnError(this CakeTaskBuilder builder, Action<Excep
return OnError(builder, (exception, context) => errorHandler(exception));
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="errorHandler">The error handler.</param>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder OnError(this CakeTaskBuilder builder, Func<Exception, Task> errorHandler)
{
if (errorHandler == null)
{
throw new ArgumentNullException(nameof(errorHandler));
}

return OnError(builder, async (exception, context) => await errorHandler(exception));
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
Expand All @@ -73,6 +106,23 @@ public static CakeTaskBuilder OnError(this CakeTaskBuilder builder, Action<Excep
return builder;
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="errorHandler">The error handler.</param>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder OnError(this CakeTaskBuilder builder, Func<Exception, ICakeContext, Task> errorHandler)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}

builder.Target.SetErrorHandler(errorHandler);
return builder;
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
Expand All @@ -86,6 +136,19 @@ public static CakeTaskBuilder OnError<TData>(this CakeTaskBuilder builder, Actio
return OnError<TData>(builder, (exception, data) => errorHandler(data));
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="errorHandler">The error handler.</param>
/// <typeparam name="TData">The extra data to operate with inside the error handler.</typeparam>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder OnError<TData>(this CakeTaskBuilder builder, Func<TData, Task> errorHandler)
where TData : class
{
return OnError<TData>(builder, async (exception, data) => await errorHandler(data));
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
Expand All @@ -99,6 +162,19 @@ public static CakeTaskBuilder OnError<TData>(this CakeTaskBuilder builder, Actio
return OnError<TData>(builder, (exception, context, data) => errorHandler(exception, data));
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="errorHandler">The error handler.</param>
/// <typeparam name="TData">The extra data to operate with inside the error handler.</typeparam>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder OnError<TData>(this CakeTaskBuilder builder, Func<Exception, TData, Task> errorHandler)
where TData : class
{
return OnError<TData>(builder, async (exception, context, data) => await errorHandler(exception, data));
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
Expand All @@ -116,6 +192,23 @@ public static CakeTaskBuilder OnError<TData>(this CakeTaskBuilder builder, Actio
});
}

/// <summary>
/// Adds an error handler to be executed if an exception occurs in the task.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="errorHandler">The error handler.</param>
/// <typeparam name="TData">The extra data to operate with inside the error handler.</typeparam>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder OnError<TData>(this CakeTaskBuilder builder, Func<Exception, ICakeContext, TData, Task> errorHandler)
where TData : class
{
return OnError(builder, async (exception, context) =>
{
var data = context.Data.Get<TData>();
await errorHandler(exception, context, data);
});
}

/// <summary>
/// Adds a finally handler to be executed after the task have finished executing.
/// </summary>
Expand All @@ -132,6 +225,22 @@ public static CakeTaskBuilder Finally(this CakeTaskBuilder builder, Action final
return builder;
}

/// <summary>
/// Adds a finally handler to be executed after the task have finished executing.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="finallyHandler">The finally handler.</param>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder Finally(this CakeTaskBuilder builder, Func<Task> finallyHandler)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Target.SetFinallyHandler(finallyHandler);
return builder;
}

/// <summary>
/// Adds an error reporter for the task to be executed when an exception is thrown from the task.
/// This action is invoked before the error handler, but gives no opportunity to recover from the error.
Expand All @@ -148,5 +257,22 @@ public static CakeTaskBuilder ReportError(this CakeTaskBuilder builder, Action<E
builder.Target.SetErrorReporter(errorReporter);
return builder;
}

/// <summary>
/// Adds an error reporter for the task to be executed when an exception is thrown from the task.
/// This action is invoked before the error handler, but gives no opportunity to recover from the error.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="errorReporter">The finally handler.</param>
/// <returns>The same <see cref="CakeTaskBuilder"/> instance so that multiple calls can be chained.</returns>
public static CakeTaskBuilder ReportError(this CakeTaskBuilder builder, Func<Exception, Task> errorReporter)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
builder.Target.SetErrorReporter(errorReporter);
return builder;
}
}
}
90 changes: 87 additions & 3 deletions src/Cake.Core/CakeTaskExtensions.cs
Expand Up @@ -70,7 +70,35 @@ public static void SetErrorHandler(this CakeTask task, Action<Exception, ICakeCo
{
throw new CakeException("There can only be one error handler per task.");
}
task.ErrorHandler = errorHandler ?? throw new ArgumentNullException(nameof(errorHandler));

if (errorHandler is null)
{
throw new ArgumentNullException(nameof(errorHandler));
}

task.ErrorHandler = async (ex, context) => errorHandler(ex, context);
}

/// <summary>
/// Sets the task's error handler.
/// </summary>
/// <param name="task">The task.</param>
/// <param name="errorHandler">The error handler.</param>
/// <exception cref="CakeException">There can only be one error handler per task.</exception>
/// <exception cref="ArgumentNullException"><paramref name="errorHandler"/> is null.</exception>
public static void SetErrorHandler(this CakeTask task, Func<Exception, ICakeContext, Task> errorHandler)
{
if (task.ErrorHandler != null)
{
throw new CakeException("There can only be one error handler per task.");
}

if (errorHandler is null)
{
throw new ArgumentNullException(nameof(errorHandler));
}

task.ErrorHandler = errorHandler;
}

/// <summary>
Expand All @@ -86,7 +114,35 @@ public static void SetErrorReporter(this CakeTask task, Action<Exception> errorR
{
throw new CakeException("There can only be one error reporter per task.");
}
task.ErrorReporter = errorReporter ?? throw new ArgumentNullException(nameof(errorReporter));

if (errorReporter is null)
{
throw new ArgumentNullException(nameof(errorReporter));
}

task.ErrorReporter = async (ex) => errorReporter(ex);
}

/// <summary>
/// Sets the task's error reporter.
/// </summary>
/// <param name="task">The task.</param>
/// <param name="errorReporter">The error reporter.</param>
/// <exception cref="CakeException">There can only be one error reporter per task.</exception>
/// <exception cref="ArgumentNullException"><paramref name="errorReporter"/> is null.</exception>
public static void SetErrorReporter(this CakeTask task, Func<Exception, Task> errorReporter)
{
if (task.ErrorReporter != null)
{
throw new CakeException("There can only be one error reporter per task.");
}

if (errorReporter is null)
{
throw new ArgumentNullException(nameof(errorReporter));
}

task.ErrorReporter = errorReporter;
}

/// <summary>
Expand All @@ -102,7 +158,35 @@ public static void SetFinallyHandler(this CakeTask task, Action finallyHandler)
{
throw new CakeException("There can only be one finally handler per task.");
}
task.FinallyHandler = finallyHandler ?? throw new ArgumentNullException(nameof(finallyHandler));

if (finallyHandler is null)
{
throw new ArgumentNullException(nameof(finallyHandler));
}

task.FinallyHandler = async () => finallyHandler();
}

/// <summary>
/// Sets the task's finally handler.
/// </summary>
/// <param name="task">The task.</param>
/// <param name="finallyHandler">The finally handler.</param>
/// <exception cref="CakeException">There can only be one finally handler per task.</exception>
/// <exception cref="ArgumentNullException"><paramref name="finallyHandler"/> is null.</exception>
public static void SetFinallyHandler(this CakeTask task, Func<Task> finallyHandler)
{
if (task.FinallyHandler != null)
{
throw new CakeException("There can only be one finally handler per task.");
}

if (finallyHandler is null)
{
throw new ArgumentNullException(nameof(finallyHandler));
}

task.FinallyHandler = finallyHandler;
}

/// <summary>
Expand Down

0 comments on commit 878aab8

Please sign in to comment.