Skip to content

Commit

Permalink
Merge pull request cake-contrib#972 from nils-a/feature/cake-contribG…
Browse files Browse the repository at this point in the history
…H-510

(cake-contrib#510) post to mastodon on successful publishing
  • Loading branch information
gep13 authored Aug 1, 2024
2 parents 65a4f51 + b293d0a commit 609bf32
Show file tree
Hide file tree
Showing 14 changed files with 434 additions and 192 deletions.
1 change: 1 addition & 0 deletions Source/Cake.Recipe/Content/addins.cake
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#addin nuget:?package=Cake.Transifex&version=1.0.1
#addin nuget:?package=Cake.Twitter&version=2.0.0
#addin nuget:?package=Cake.Wyam&version=2.2.13
#addin nuget:?package=Cake.Mastodon&version=1.1.0

#load nuget:?package=Cake.Issues.Recipe&version=1.3.2

Expand Down
43 changes: 10 additions & 33 deletions Source/Cake.Recipe/Content/build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,12 @@ Teardown<BuildVersion>((context, buildVersion) =>
!BuildParameters.IsRunningIntegrationTests)
{
var messageArguments = BuildParameters.MessageArguments(buildVersion);
if (BuildParameters.CanPostToTwitter && BuildParameters.ShouldPostToTwitter)
foreach(var reporter in BuildParameters.SuccessReporters)
{
SendMessageToTwitter(string.Format(BuildParameters.TwitterMessage, messageArguments));
}

if (BuildParameters.CanPostToMicrosoftTeams && BuildParameters.ShouldPostToMicrosoftTeams)
{
SendMessageToMicrosoftTeams(string.Format(BuildParameters.MicrosoftTeamsMessage, messageArguments));
}

if (BuildParameters.CanSendEmail && BuildParameters.ShouldSendEmail && !string.IsNullOrEmpty(BuildParameters.EmailRecipient))
{
var subject = $"Continuous Integration Build of {BuildParameters.Title} completed successfully";
var message = new StringBuilder();
message.AppendLine(string.Format(BuildParameters.StandardMessage, messageArguments) + "<br/>");
message.AppendLine("<br/>");
message.AppendLine($"<strong>Name</strong>: {BuildParameters.Title}<br/>");
message.AppendLine($"<strong>Version</strong>: {buildVersion.SemVersion}<br/>");
message.AppendLine($"<strong>Configuration</strong>: {BuildParameters.Configuration}<br/>");
message.AppendLine($"<strong>Target</strong>: {BuildParameters.Target}<br/>");
message.AppendLine($"<strong>Cake version</strong>: {buildVersion.CakeVersion}<br/>");
message.AppendLine($"<strong>Cake.Recipe version</strong>: {BuildMetaData.Version}<br/>");

SendEmail(subject, message.ToString(), BuildParameters.EmailRecipient, BuildParameters.EmailSenderName, BuildParameters.EmailSenderAddress);
if(reporter.ShouldBeUsed && reporter.CanBeUsed)
{
reporter.ReportSuccess(context, buildVersion);
}
}
}
}
Expand All @@ -69,17 +51,12 @@ Teardown<BuildVersion>((context, buildVersion) =>
BuildParameters.IsMainRepository &&
!BuildParameters.IsRunningIntegrationTests)
{
if (BuildParameters.CanPostToSlack && BuildParameters.ShouldPostToSlack)
{
SendMessageToSlackChannel("Continuous Integration Build of " + BuildParameters.Title + " just failed :-(");
}

if (BuildParameters.CanSendEmail && BuildParameters.ShouldSendEmail && !string.IsNullOrEmpty(BuildParameters.EmailRecipient))
foreach(var reporter in BuildParameters.FailureReporters)
{
var subject = $"Continuous Integration Build of {BuildParameters.Title} failed";
var message = context.ThrownException.ToString().Replace(System.Environment.NewLine, "<br/>");

SendEmail(subject, message, BuildParameters.EmailRecipient, BuildParameters.EmailSenderName, BuildParameters.EmailSenderAddress);
if(reporter.ShouldBeUsed && reporter.CanBeUsed)
{
reporter.ReportFailure(context, buildVersion, context.ThrownException);
}
}
}
}
Expand Down
19 changes: 19 additions & 0 deletions Source/Cake.Recipe/Content/credentials.cake
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ public class WyamCredentials
}
}

public class MastodonCredentials
{
public string AccessToken { get; private set; }
public string InstanceUrl { get; private set; }

public MastodonCredentials(string accessToken, string instanceUrl)
{
AccessToken = accessToken;
InstanceUrl = instanceUrl;
}
}

public static GitHubCredentials GetGitHubCredentials(ICakeContext context)
{
string token = null;
Expand Down Expand Up @@ -224,3 +236,10 @@ public static WyamCredentials GetWyamCredentials(ICakeContext context)
context.EnvironmentVariable(Environment.WyamDeployRemoteVariable),
context.EnvironmentVariable(Environment.WyamDeployBranchVariable));
}

public static MastodonCredentials GetMastodonCredentials(ICakeContext context)
{
return new MastodonCredentials(
context.EnvironmentVariable(Environment.MastodonAccessTokenVariable),
context.EnvironmentVariable(Environment.MastodonInstanceUrlVariable));
}
117 changes: 79 additions & 38 deletions Source/Cake.Recipe/Content/email.cake
Original file line number Diff line number Diff line change
@@ -1,50 +1,91 @@
using Cake.Email.Common;

///////////////////////////////////////////////////////////////////////////////
// HELPER METHODS
///////////////////////////////////////////////////////////////////////////////

public void SendEmail(string subject, string message, string recipient, string senderName, string senderAddress)
public class EmailReporter : ISuccessReporter, IFailureReporter
{
Information("Sending email...");
private EmailCredentials _credentials;

public EmailReporter(EmailCredentials credentials)
{
_credentials = credentials;
}

// The recipient parameter can contain a single email address or a comma/semi-colon separated list of email addresses
var recipients = recipient
.Split(new[] { ',', ';' }, StringSplitOptions.None)
.Select(emailAddress => new MailAddress(emailAddress))
.ToArray();
public string Name { get; } = "EMail";

try
public bool CanBeUsed
{
var result = Email.SendEmail(
senderName: senderName,
senderAddress: senderAddress,
recipients: recipients,
subject: subject,
htmlContent: message,
textContent: null,
attachments: null,
settings: new EmailSettings
{
SmtpHost = BuildParameters.Email.SmtpHost,
Port = BuildParameters.Email.Port,
EnableSsl = BuildParameters.Email.EnableSsl,
Username = BuildParameters.Email.Username,
Password = BuildParameters.Email.Password
}
);
get => !string.IsNullOrEmpty(_credentials.SmtpHost)
&& !string.IsNullOrEmpty(BuildParameters.EmailRecipient);
}

public bool ShouldBeUsed { get; set; }

public void ReportSuccess(ICakeContext context, BuildVersion buildVersion)
{
var subject = $"Continuous Integration Build of {BuildParameters.Title} completed successfully";
var messageArguments = BuildParameters.MessageArguments(buildVersion);
var message = new StringBuilder();
message.AppendLine(string.Format(BuildParameters.StandardMessage, messageArguments) + "<br/>");
message.AppendLine("<br/>");
message.AppendLine($"<strong>Name</strong>: {BuildParameters.Title}<br/>");
message.AppendLine($"<strong>Version</strong>: {buildVersion.SemVersion}<br/>");
message.AppendLine($"<strong>Configuration</strong>: {BuildParameters.Configuration}<br/>");
message.AppendLine($"<strong>Target</strong>: {BuildParameters.Target}<br/>");
message.AppendLine($"<strong>Cake version</strong>: {buildVersion.CakeVersion}<br/>");
message.AppendLine($"<strong>Cake.Recipe version</strong>: {BuildMetaData.Version}<br/>");

SendEmail(context, subject, message.ToString(), BuildParameters.EmailRecipient, BuildParameters.EmailSenderName, BuildParameters.EmailSenderAddress);
}

public void ReportFailure(ICakeContext context, BuildVersion _, Exception thrownException)
{
var subject = $"Continuous Integration Build of {BuildParameters.Title} failed";
var message = thrownException.ToString().Replace(System.Environment.NewLine, "<br/>");

SendEmail(context, subject, message, BuildParameters.EmailRecipient, BuildParameters.EmailSenderName, BuildParameters.EmailSenderAddress);
}

if (result.Ok)
private void SendEmail(ICakeContext context, string subject, string message, string recipient, string senderName, string senderAddress)
{
context.Information("Sending email...");

// The recipient parameter can contain a single email address or a comma/semi-colon separated list of email addresses
var recipients = recipient
.Split(new[] { ',', ';' }, StringSplitOptions.None)
.Select(emailAddress => new MailAddress(emailAddress))
.ToArray();

try
{
Information("Email successfully sent");
var result = context.Email().SendEmail(
senderName: senderName,
senderAddress: senderAddress,
recipients: recipients,
subject: subject,
htmlContent: message,
textContent: null,
attachments: null,
settings: new EmailSettings
{
SmtpHost = _credentials.SmtpHost,
Port = _credentials.Port,
EnableSsl = _credentials.EnableSsl,
Username = _credentials.Username,
Password = _credentials.Password
}
);

if (result.Ok)
{
context.Information("Email successfully sent");
}
else
{
context.Error("Failed to send email: {0}", result.Error);
}
}
else
catch(Exception ex)
{
Error("Failed to send email: {0}", result.Error);
context.Error("{0}", ex);
}
}
catch(Exception ex)
{
Error("{0}", ex);
}
}
}
8 changes: 7 additions & 1 deletion Source/Cake.Recipe/Content/environment.cake
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public static class Environment
public static string WyamAccessTokenVariable { get; private set; }
public static string WyamDeployRemoteVariable { get; private set; }
public static string WyamDeployBranchVariable { get; private set; }
public static string MastodonAccessTokenVariable { get; private set; }
public static string MastodonInstanceUrlVariable { get; private set; }

public static void SetVariableNames(
string githubTokenVariable = null,
Expand All @@ -41,7 +43,9 @@ public static class Environment
string transifexApiTokenVariable = null,
string wyamAccessTokenVariable = null,
string wyamDeployRemoteVariable = null,
string wyamDeployBranchVariable = null)
string wyamDeployBranchVariable = null,
string mastodonAccessTokenVariable = null,
string mastodonInstanceUrlVariable = null)
{
GithubTokenVariable = githubTokenVariable ?? "GITHUB_PAT";
SlackTokenVariable = slackTokenVariable ?? "SLACK_TOKEN";
Expand All @@ -63,5 +67,7 @@ public static class Environment
WyamAccessTokenVariable = wyamAccessTokenVariable ?? "WYAM_ACCESS_TOKEN";
WyamDeployRemoteVariable = wyamDeployRemoteVariable ?? "WYAM_DEPLOY_REMOTE";
WyamDeployBranchVariable = wyamDeployBranchVariable ?? "WYAM_DEPLOY_BRANCH";
MastodonAccessTokenVariable = mastodonAccessTokenVariable ?? "MASTODON_ACCESS_TOKEN";
MastodonInstanceUrlVariable = mastodonInstanceUrlVariable ?? "MASTODON_INSTANCE_URL";
}
}
43 changes: 43 additions & 0 deletions Source/Cake.Recipe/Content/mastodon.cake
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
public class MastodonReporter : SuccessReporter
{
private MastodonCredentials _credentials;
private string _messageTemplate;

public MastodonReporter(MastodonCredentials credentials, string messageTemplate)
{
_credentials = credentials;
_messageTemplate = messageTemplate;
}

public override string Name { get; } = "Mastodon";

public override bool CanBeUsed
{
get => !string.IsNullOrEmpty(_credentials.AccessToken) &&
!string.IsNullOrEmpty(_credentials.InstanceUrl);
}


public override void ReportSuccess(ICakeContext context, BuildVersion buildVersion)
{
try
{
context.Information("Sending message to Mastodon...");

var messageArguments = BuildParameters.MessageArguments(buildVersion);
var message = string.Format(_messageTemplate, messageArguments);
var idempotencyKey = Guid.NewGuid().ToString("d");

context.MastodonSendToot(_credentials.InstanceUrl,
_credentials.AccessToken,
message,
idempotencyKey);

context.Information("Message successfully sent.");
}
catch(Exception ex)
{
context.Error("{0}", ex);
}
}
}
44 changes: 31 additions & 13 deletions Source/Cake.Recipe/Content/microsoftteams.cake
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
///////////////////////////////////////////////////////////////////////////////
// HELPER METHODS
///////////////////////////////////////////////////////////////////////////////

public void SendMessageToMicrosoftTeams(string message)
public class MsTeamsReporter : SuccessReporter
{
try
private MicrosoftTeamsCredentials _credentials;
private string _messageTemplate;

public MsTeamsReporter(MicrosoftTeamsCredentials credentials, string messageTemplate)
{
Information("Sending message to Microsoft Teams...");
_credentials = credentials;
_messageTemplate = messageTemplate;
}

MicrosoftTeamsPostMessage(message,
new MicrosoftTeamsSettings {
IncomingWebhookUrl = BuildParameters.MicrosoftTeams.WebHookUrl
});
public override string Name { get; } = "MicrosoftTeams";

public override bool CanBeUsed
{
get => !string.IsNullOrEmpty(_credentials.WebHookUrl);
}
catch(Exception ex)

public override void ReportSuccess(ICakeContext context, BuildVersion buildVersion)
{
Error("{0}", ex);
try
{
context.Information("Sending message to Microsoft Teams...");

var messageArguments = BuildParameters.MessageArguments(buildVersion);
var message = string.Format(_messageTemplate, messageArguments);

context.MicrosoftTeamsPostMessage(message,
new MicrosoftTeamsSettings {
IncomingWebhookUrl = _credentials.WebHookUrl
});

}
catch(Exception ex)
{
context.Error("{0}", ex);
}
}
}
Loading

0 comments on commit 609bf32

Please sign in to comment.