Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 75 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ jobs:
with:
fetch-depth: 0

# global.json pins the SDK with rollForward disable, so install exactly that
# version rather than whatever 10.0.x happens to be latest.
- name: Setup .NET
uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
global-json-file: global.json

- name: Restore
run: dotnet restore
Expand All @@ -36,6 +38,77 @@ jobs:
name: packages
path: ./artifacts/*.nupkg

# Collects line coverage and publishes it to Codacy. Runs on the self-hosted
# pdl-public scale set rather than a GitHub-hosted runner.
# pdl-public is the hardened scale set that may serve a public repository: a
# fork pull request is untrusted code, so it has no dind, no privileged
# container, no hostPath and nothing shared between jobs.
#
# Only tests that need no credentials run here. Every current test uses a
# mocked HttpMessageHandler, so none calls live Slack; any future test that
# needs a real webhook URL must carry [Trait("Category", "Integration")],
# which the filter below excludes.
coverage:
runs-on: [pdl-public]

env:
DOTNET_NOLOGO: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
# The actions-runner image does not offer the Node version several of these
# actions request by default; without this they fail before their first step.
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

steps:
- name: Checkout
uses: actions/checkout@v7
with:
fetch-depth: 0 # Nerdbank.GitVersioning needs the full history.

- name: Setup .NET
uses: actions/setup-dotnet@v6
env:
# The runner user cannot write /usr/share/dotnet, the default install location.
DOTNET_INSTALL_DIR: ${{ runner.temp }}/dotnet
with:
global-json-file: global.json

- name: Build tests
run: dotnet build Slack.Webhooks.Tests/PanoramicData.Slack.Webhooks.Tests.csproj --configuration Debug

# The test project is a Microsoft.Testing.Platform application
# (UseMicrosoftTestingPlatformRunner), so coverage is collected by running the
# test executable directly with Microsoft.Testing.Extensions.CodeCoverage rather
# than through `dotnet test`. On Linux the executable has no .exe extension.
# coverage.config ports coverlet's generated-code exclusions so figures stay
# comparable across the estate.
- name: Run tests with coverage
run: >-
./Slack.Webhooks.Tests/bin/Debug/net10.0/PanoramicData.Slack.Webhooks.Tests
--filter-not-trait "Category=Integration"
--coverage
--coverage-settings coverage.config
--coverage-output-format cobertura
--coverage-output coverage.cobertura.xml

# continue-on-error: a Codacy outage must not turn a passing test run red. The
# trade-off is that an expired or missing project token fails silently, so
# check the step log for "Coverage received successfully".
- name: Upload coverage to Codacy
continue-on-error: true
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: Slack.Webhooks.Tests/bin/Debug/net10.0/TestResults/coverage.cobertura.xml

- name: Upload coverage artifact
if: always()
continue-on-error: true
uses: actions/upload-artifact@v7
with:
name: coverage
path: Slack.Webhooks.Tests/bin/Debug/net10.0/TestResults/coverage.cobertura.xml
retention-days: 7

publish:
needs: build
runs-on: ubuntu-latest
Expand All @@ -61,4 +134,4 @@ jobs:
user: david_n_m_bond

- name: Push to NuGet
run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ steps.login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Thank you for your interest in contributing to this project!
- Use xUnit v3 for all tests
- Use AwesomeAssertions for fluent assertions
- Ensure all existing tests pass before submitting a PR
- Tests that call live Slack or need a real webhook URL must carry `[Trait("Category", "Integration")]`; CI's coverage job excludes them because it runs without credentials

## License

Expand Down
1 change: 0 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<PackageVersion Include="Moq" Version="4.20.72" />
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.10.94" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="4.0.0" />
<PackageVersion Include="xunit.v3" Version="4.0.1" />
</ItemGroup>
Expand Down
20 changes: 7 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ Even simpler integration with Slack's Incoming/Outgoing webhooks API for .net

### IMPORTANT

On Feb 19th 2020 Slack will end support for TLS version 1.0 and 1.1. This means you may (depending on your .NET version) need to force the use of TLS1.2.
This package targets **.NET 10** (`net10.0`) only. Earlier releases targeted .NET Standard 2.0, which also made them usable from .NET Framework; that is no longer the case. Projects on .NET Framework, or on a .NET version earlier than 10, should stay on the last .NET Standard 2.0 release.

If you receive an error stating that "The underlying connection was closed:" it's quite possibly a TLS issue. You can work around this by setting the default TLS version using the following:

```csharp
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
```
Slack ended support for TLS 1.0 and 1.1 on 19 February 2020. .NET 10 negotiates TLS 1.2 or later by default, so no `ServicePointManager` workaround is needed.

### Change Log

#### Unreleased

- Target .NET 10 only; drop .NET Standard 2.0 (and therefore .NET Framework) support

#### v1.1.4

- Add Block elements to Attachments
Expand Down Expand Up @@ -56,7 +56,7 @@ Requirements:

1. You must first enable the Webhooks integration for your Slack Account to get the Token. You can enable it here: https://slack.com/services/new/incoming-webhook
2. Slack.Webhooks depends on JSON.net
3. Compatible with .NET 4.5+ and .NET Core. If you need .NET 3.5/4 you can use an older release, but this may be out of date.
3. Requires .NET 10 or later.

Download:

Expand All @@ -66,12 +66,6 @@ Package is hosted on [Nuget](https://www.nuget.org/packages/Slack.Webhooks/) and
PM> Install-Package Slack.Webhooks
```

For older .NET framework support:

```
PM> Install-Package Slack.Webhooks -Version 0.1.8
```

Then, create a SlackClient with your Webhook URL.

```csharp
Expand Down
2 changes: 1 addition & 1 deletion Slack.Webhooks.Tests/EmojiShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void DeserializeToObject()
var deserialized = JsonConvert.DeserializeObject<string>("\":ghost:\"");

//assert
Assert.Equal(Emoji.Ghost.ToString(), deserialized.ToString());
Assert.Equal(Emoji.Ghost.ToString(), deserialized);
}

[Fact]
Expand Down
22 changes: 8 additions & 14 deletions Slack.Webhooks.Tests/PanoramicData.Slack.Webhooks.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,25 @@
<Deterministic>False</Deterministic>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Test code uses NRT-unaware patterns (null initializers, mocked nullables); keep strict NRT for the library only. -->
<Nullable>disable</Nullable>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Slack.Webhooks\PanoramicData.Slack.Webhooks.csproj">
<Project>{53751b1b-a63e-4e4f-988c-bc783e68b15f}</Project>
<Name>Slack.Webhooks</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<ProjectReference Include="..\Slack.Webhooks\PanoramicData.Slack.Webhooks.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="AwesomeAssertions" />
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" PrivateAssets="all" />
</ItemGroup>
</Project>
</Project>
10 changes: 7 additions & 3 deletions Slack.Webhooks.Tests/SlackClientFixtures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@ public void ShouldContainSerializedMessage()
{
//arrange
const string hookUrl = "https://hooks.slack.com/invalid";
SlackMessage postedMessage = null;
SlackMessage? postedMessage = null;
var httpMessageHandler = GetMockHttpMessageHandler(callback: (req, token) =>
{
Assert.NotNull(req.Content);
var json = req.Content.ReadAsStringAsync(token).GetAwaiter().GetResult();
postedMessage = SlackClient.DeserializeObject(json);
});
Expand Down Expand Up @@ -121,8 +122,11 @@ public void ShouldPostToMultipleChannels()
var channelsPostedTo = new List<string>();
var httpMessageHandler = GetMockHttpMessageHandler(callback: (req, token) =>
{
var json = req.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Assert.NotNull(req.Content);
var json = req.Content.ReadAsStringAsync(token).GetAwaiter().GetResult();
var postedMessage = SlackClient.DeserializeObject(json);
Assert.NotNull(postedMessage);
Assert.NotNull(postedMessage.Channel);
channelsPostedTo.Add(postedMessage.Channel);
});

Expand All @@ -142,7 +146,7 @@ public void ShouldPostToMultipleChannels()
}
}

private static Mock<HttpMessageHandler> GetMockHttpMessageHandler(string response = "OK", Action<HttpRequestMessage, CancellationToken> callback = null)
private static Mock<HttpMessageHandler> GetMockHttpMessageHandler(string response = "OK", Action<HttpRequestMessage, CancellationToken>? callback = null)
{
callback ??= new Action<HttpRequestMessage, CancellationToken>(delegate (HttpRequestMessage m, CancellationToken t) { });

Expand Down
41 changes: 0 additions & 41 deletions Slack.Webhooks.Tests/packages.config

This file was deleted.

5 changes: 2 additions & 3 deletions Slack.Webhooks/PanoramicData.Slack.Webhooks.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<AnalysisLevel>latest-recommended</AnalysisLevel>
<AnalysisMode>recommended</AnalysisMode>
Expand All @@ -20,14 +20,13 @@
<PackageIcon>slack.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>slack;webhook;webhooks</PackageTags>
<PackageReleaseNotes>First release as .NET Standard 2.0</PackageReleaseNotes>
<PackageReleaseNotes>Now targets .NET 10 only. .NET Standard 2.0, and therefore .NET Framework, is no longer supported.</PackageReleaseNotes>
<IncludeSymbols>True</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageId>PanoramicData.Slack.Webhooks</PackageId>
<ImplicitUsings>enable</ImplicitUsings>
<NeutralResourcesLanguage>en</NeutralResourcesLanguage>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Content Include="Panoramic Data.ico" />
Expand Down
3 changes: 2 additions & 1 deletion Slack.Webhooks/SlackClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ public class SlackClient : ISlackClient, IDisposable
public SlackClient(string webhookUrl, int timeoutMs = 100, HttpClient? httpClient = null)
{
_httpClient = httpClient ?? new HttpClient();
if (!Uri.TryCreate(webhookUrl, UriKind.Absolute, out _webhookUri))
if (!Uri.TryCreate(webhookUrl, UriKind.Absolute, out var webhookUri))
throw new ArgumentException("Please enter a valid webhook url");
_webhookUri = webhookUri;
_timeoutMs = timeoutMs;
}

Expand Down
33 changes: 33 additions & 0 deletions coverage.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Microsoft.Testing.Extensions.CodeCoverage settings.

The attribute exclusions are not optional if figures are to stay comparable across the estate: the
Microsoft collector includes generated code by default, where coverlet excluded it. Porting them is
worth several points of apparent coverage on a repository with generated clients.
-->
<Configuration>
<CodeCoverage>
<ModulePaths>
<Exclude>
<ModulePath>.*Test\.dll$</ModulePath>
<ModulePath>.*Tests\.dll$</ModulePath>
</Exclude>
</ModulePaths>
<Attributes>
<Exclude>
<Attribute>^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$</Attribute>
<Attribute>^System\.Runtime\.CompilerServices\.CompilerGeneratedAttribute$</Attribute>
<Attribute>^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$</Attribute>
<Attribute>^System\.ObsoleteAttribute$</Attribute>
</Exclude>
</Attributes>
<Sources>
<Exclude>
<Source>.*\\obj\\.*</Source>
</Exclude>
</Sources>
<UseVerifiableInstrumentation>False</UseVerifiableInstrumentation>
<CollectFromChildProcesses>True</CollectFromChildProcesses>
</CodeCoverage>
</Configuration>
4 changes: 2 additions & 2 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"sdk": {
"version": "10.0.400",
"rollForward": "latestMinor"
"version": "10.0.401",
"rollForward": "disable"
},
"test": {
"runner": "Microsoft.Testing.Platform"
Expand Down
Loading