diff --git a/README.md b/README.md index 41e4f67..6af8069 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Potty Mouth: GitHub Action -> 🤬 Profane content filter +> This repository contains the source code for a profane content filter 🤬. [![.NET](https://github.com/IEvangelist/profanity-filter/actions/workflows/dotnet.yml/badge.svg)](https://github.com/IEvangelist/profanity-filter/actions/workflows/dotnet.yml) [![Dogfood](https://github.com/IEvangelist/profanity-filter/actions/workflows/dogfood.yml/badge.svg)](https://github.com/IEvangelist/profanity-filter/actions/workflows/dogfood.yml) @@ -54,7 +54,7 @@ jobs: id: profanity-filter with: token: ${{ secrets.GITHUB_TOKEN }} - # See https://github.com/IEvangelist/profanity-filter?tab=readme-ov-file#-replacement-strategies + # See https://bit.ly/potty-mouth-replacement-strategies replacement-strategy: Emoji # See Replacement strategy ``` @@ -69,7 +69,7 @@ If you already have an existing workflow that is triggered `on/issues|pull_reque id: profanity-filter with: token: ${{ secrets.GITHUB_TOKEN }} - # See https://github.com/IEvangelist/profanity-filter?tab=readme-ov-file#-replacement-strategies + # See https://bit.ly/potty-mouth-replacement-strategies replacement-strategy: FirstLetterThenAsterisk ``` @@ -87,6 +87,7 @@ The following table describes each input: | `token` | The GitHub token used to update the issues or pull requests with.

Example, `${{ secrets.GITHUB_TOKEN }}`. | `true` | | `replacement-strategy` | The type of replacement method to use when profane content is filtered. | `false` (default: `asterisk`) | | `include-update-note` | A `boolean` value to indicate if the action should include a note in the issue or pull request body when profane content is replaced. | `false` (default: `true`) | +| `include-confused-reaction` | A `boolean` value to indicate if the action should react to the issue or pull request with the confused 😕 reaction. | `false` (default: `true`) | ### 😵 Replacement strategies @@ -125,7 +126,7 @@ Consider the following automatically applied label to an issue that contains pro When profane content is detected, the action will update the issue or pull request by: - Replacing any found profane content with the configured replacement strategy. -- ~~Reacting to the issue or pull request with the [confused 😕 reaction](https://docs.github.com/rest/reactions/reactions).~~ +- Reacting to the issue or pull request with the [confused 😕 reaction](https://docs.github.com/rest/reactions/reactions). - Conditionally applying the `profane content 🤬` label if found in the repository. - Reporting the profane content in the workflow summary as a detailed table. @@ -137,7 +138,8 @@ flowchart TD --> B[Contains Profane Content?] B -->|YES| C(Apply Filter) --> E(All swear words are filtered, for example sw**r) - --o F[Job Summary] + --> F(React to and label profane content) + --o G[Job Summary] B --o|NO| D{{Stop}} ~~~A ``` diff --git a/action.yml b/action.yml index cf93dcc..850f3de 100644 --- a/action.yml +++ b/action.yml @@ -20,6 +20,11 @@ inputs: 'Whether to include a note in the issue or pull request body indicating that the content was filtered.' required: false default: 'true' + include-confused-reaction: + description: + 'Whether to include a confused reaction on the issue or pull request when profane content is filtered.' + required: false + default: 'true' runs: using: 'docker' diff --git a/src/ProfanityFilter.Action/GlobalUsings.cs b/src/ProfanityFilter.Action/GlobalUsings.cs index fa6ff48..c3b4f53 100644 --- a/src/ProfanityFilter.Action/GlobalUsings.cs +++ b/src/ProfanityFilter.Action/GlobalUsings.cs @@ -1,6 +1,7 @@ // Copyright (c) David Pine. All rights reserved. // Licensed under the MIT License. +global using System.Diagnostics; global using System.Diagnostics.CodeAnalysis; global using Actions.Core.Extensions; diff --git a/src/ProfanityFilter.Action/ProfanityProcessor.Issue.cs b/src/ProfanityFilter.Action/ProfanityProcessor.Issue.cs index a491f69..e0f3ba0 100644 --- a/src/ProfanityFilter.Action/ProfanityProcessor.Issue.cs +++ b/src/ProfanityFilter.Action/ProfanityProcessor.Issue.cs @@ -52,7 +52,10 @@ private async Task HandleIssueAsync( await client.UpdateIssueAsync((int)issueNumber, issueUpdate); - await client.AddReactionAsync(issueNumber, ReactionContent.Confused); + if (core.GetBoolInput("include-confused-reaction")) + { + await client.AddReactionAsync(issueNumber, ReactionContent.Confused); + } } } finally diff --git a/src/ProfanityFilter.Action/ProfanityProcessor.IssueComment.cs b/src/ProfanityFilter.Action/ProfanityProcessor.IssueComment.cs index 648ad01..a499f7b 100644 --- a/src/ProfanityFilter.Action/ProfanityProcessor.IssueComment.cs +++ b/src/ProfanityFilter.Action/ProfanityProcessor.IssueComment.cs @@ -39,8 +39,11 @@ private async Task HandleIssueCommentAsync( await client.UpdateIssueCommentAsync(issueCommentId, finalBodyUpdate); - var issueNumber = (int)_context!.Payload!.Issue!.Number; - await client.AddReactionAsync(issueNumber, ReactionContent.Confused); + if (core.GetBoolInput("include-confused-reaction")) + { + var issueNumber = (int)_context!.Payload!.Issue!.Number; + await client.AddReactionAsync(issueNumber, ReactionContent.Confused); + } } } finally diff --git a/src/ProfanityFilter.Action/ProfanityProcessor.PullRequest.cs b/src/ProfanityFilter.Action/ProfanityProcessor.PullRequest.cs index 4a168fb..b3b99ab 100644 --- a/src/ProfanityFilter.Action/ProfanityProcessor.PullRequest.cs +++ b/src/ProfanityFilter.Action/ProfanityProcessor.PullRequest.cs @@ -38,8 +38,11 @@ private async Task HandlePullRequestAsync( await client.UpdatePullRequestAsync( (int)pullRequestNumber, pullRequestUpdate, label?.Name); - await client.AddReactionAsync( - pullRequestNumber, ReactionContent.Confused); + if (core.GetBoolInput("include-confused-reaction")) + { + await client.AddReactionAsync( + pullRequestNumber, ReactionContent.Confused); + } } } finally diff --git a/src/ProfanityFilter.Action/ProfanityProcessor.cs b/src/ProfanityFilter.Action/ProfanityProcessor.cs index 62b6348..ff85539 100644 --- a/src/ProfanityFilter.Action/ProfanityProcessor.cs +++ b/src/ProfanityFilter.Action/ProfanityProcessor.cs @@ -15,6 +15,7 @@ public async Task ProcessProfanityAsync() var success = true; Summary summary = new(); + var startingTimestamp = Stopwatch.GetTimestamp(); try { @@ -58,7 +59,9 @@ public async Task ProcessProfanityAsync() ContextSummaryPair contextSummaryPair = (context, summary); - await SummarizeAppliedFiltersAsync(result, contextSummaryPair); + var elapsedTime = Stopwatch.GetElapsedTime(startingTimestamp); + + await SummarizeAppliedFiltersAsync(result, contextSummaryPair, elapsedTime); } catch (Exception ex) { @@ -180,7 +183,7 @@ private async ValueTask TryApplyFilterAsync( } private static async Task SummarizeAppliedFiltersAsync( - FiltrationResult result, ContextSummaryPair contextSummaryPair) + FiltrationResult result, ContextSummaryPair contextSummaryPair, TimeSpan elapsedTime) { if (result.IsFiltered == false) { @@ -210,6 +213,8 @@ private static async Task SummarizeAppliedFiltersAsync( ```{Env.NewLine}{Env.NewLine} """); + summary.AddRawMarkdown($"> The _potty mouth_ profanity filter ran in {elapsedTime:g}."); + if (!summary.IsBufferEmpty) { await summary.WriteAsync(new() { Overwrite = true }); diff --git a/src/ProfanityFilter.Services/Internals/MatchRegistry.cs b/src/ProfanityFilter.Services/Internals/MatchRegistry.cs index 2c3b649..dd0e1fa 100644 --- a/src/ProfanityFilter.Services/Internals/MatchRegistry.cs +++ b/src/ProfanityFilter.Services/Internals/MatchRegistry.cs @@ -8,7 +8,7 @@ internal static class MatchRegistry private static readonly ConcurrentDictionary> s_registry = new(); /// - /// Registers a given for the given . + /// Registers a given with the given . /// internal static void Register(FilterParameters parameters, Match match) { diff --git a/tests/ProfanityFilter.Services.Tests/DefaultProfaneContentFilterServiceTests.cs b/tests/ProfanityFilter.Services.Tests/DefaultProfaneContentFilterServiceTests.cs index 47d14bf..16abfda 100644 --- a/tests/ProfanityFilter.Services.Tests/DefaultProfaneContentFilterServiceTests.cs +++ b/tests/ProfanityFilter.Services.Tests/DefaultProfaneContentFilterServiceTests.cs @@ -38,6 +38,28 @@ public async Task FilterProfanityAsync_Returns_Expected_Result(string? input, st } } + [Fact] + public async Task FilterProfanityAsyncMultipleParameters_Returns_Valid_Results() + { + var input = "This is fucking bullshit!"; + + // Act + var titleResult = await _sut.FilterProfanityAsync(input, + new(ReplacementStrategy.Bleep, FilterTarget.Title)); + + var bodyResult = await _sut.FilterProfanityAsync(input, + new(ReplacementStrategy.Emoji, FilterTarget.Body)); + + // Assert + Assert.Equal("This is bleep bleep!", titleResult.FinalOutput); + Assert.True(titleResult.IsFiltered); + Assert.Equal(2, titleResult.Matches.Count); + + Assert.NotEqual(input, bodyResult.FinalOutput); + Assert.True(bodyResult.IsFiltered); + Assert.Equal(2, bodyResult.Matches.Count); + } + [Fact] public async Task FilterProfanityAsyncWithEmoji_Returns_Valid_Result() {