Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Starting code and start of actions #1

Merged
merged 10 commits into from
Mar 21, 2024
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
68 changes: 68 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Plan and package for release
# On PRs, only the plan step is executed to output the version manifest.

name: Package for release
on:
workflow_dispatch: # For testing purposes
release:
types:
- released
pull_request:
branches:
- main

jobs:
plan:
name: Calculate package versions
runs-on: ubuntu-latest
outputs:
versionManifest: ${{ steps.versionManifest.outputs.versionManifest }}
steps:
- uses: actions/checkout@v4
name: Checkout
- uses: actions/cache@v4
- name: Get version manifest
shell: pwsh
id: versionManifest
run: |
Import-Module -Force .\Get-Versions.psm1
Write-Output "::debug::Generating package versions"
$versionManifest = Get-Versions
"versionManifest=$versionManifest" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
$summary = "### Version manifest `r`n" + '```json' + "`r`n" + $versionManifest + "`r`n" + '````'
$summary | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Append
build-release:
needs:
- plan
if: ${{ fromJson(needs.plan.outputs.versionManifest != null && github.event_name == 'release' }}
name: Build for (${{ matrix.os }})
runs-on: ubuntu-latest
strategy:
matrix:
os: [win, linux]
environment: release
steps:
- uses: actions/checkout@v4
name: Checkout
- uses: actions/setup-dotnet@v4
name: Setup dotnet cli
with:
global-json-file: global.json
cache: true
- name: Build and restore
shell: pwsh
env:
VERSION_MANIFEST: ${{ needs.plan.outputs.versionManifest }}
run: |
$versionManifest = ConvertFrom-Json -InputObject $env:VERSION_MANIFEST -AsHashTable
foreach ($app in $versionManifest.GetEnumerator()) {
$packageVersion = $app.Value.SemVer
Write-Output "::debug::Building package " + $app.Key + " with version " + $packageVersion
& dotnet build $app.Value.Root -c Release --os ${{ matrix.os }} --no-self-contained `
-p:PackageRequireLicenseAcceptance=true `
-p:PackageLicenseFile=LICENSE `
-p:Version=$packageVersion `
-p:PackageProjectUrl=$env:REPO_URL `
-p:RepositoryUrl=$env:REPO_URL
}

12 changes: 12 additions & 0 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

name: PR Check
on:
pull_request:
branches:
- main
types:
- opened
- review_requested

jobs:

21 changes: 21 additions & 0 deletions Get-Versions.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function Get-Versions {
$versionFiles = Get-Item -Path src/**/version.yaml | Select-Object -ExpandProperty FullName
Write-Debug "Found the following version files:"
$versionFiles | ForEach-Object { $_ | Write-Debug }

$packageVersions = @{}
$versionFiles | ForEach-Object {
Write-Debug "Reading version file $_"
$packageName = Split-Path $_ -Parent | Split-Path -Leaf
$yamlVersion = (Get-Content $_ | ConvertFrom-Yaml).version
$semver = '{0}.{1}.{2}' -f $yamlVersion.major, $yamlVersion.minor, $yamlVersion.patch
$assemblyVersion = $semver + ".0"

$packageVersions[$packageName] = @{ 'SemVer' = $semver; 'AssemblyVersion' = $assemblyVersion; 'Root' = $(Split-Path $_ -Parent)}
}

$packageVersions | ConvertTo-Json | Write-Output
}

Install-Module -Name powershell-yaml -Force -AcceptLicense
Export-ModuleMember -Function Get-Versions
13 changes: 13 additions & 0 deletions Kek.Net.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.gitignore = .gitignore
LICENSE = LICENSE
README.md = README.md
global.json = global.json
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kek.Net.AspNet", "src\Kek.Net.AspNet\Kek.Net.AspNet.csproj", "{42FE1425-3AD4-495D-9B13-F8EC5E8F1865}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kek.Net.ErrorHandling", "src\Kek.Net.ErrorHandling\Kek.Net.ErrorHandling.csproj", "{206655CC-CFCA-4F8B-A7B1-56B299A6DCA0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kek.Net.Extensions", "src\Kek.Net.Extensions\Kek.Net.Extensions.csproj", "{BFA704DC-BB88-44EE-93C9-D2258ABD1FCD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -25,5 +30,13 @@ Global
{42FE1425-3AD4-495D-9B13-F8EC5E8F1865}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42FE1425-3AD4-495D-9B13-F8EC5E8F1865}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42FE1425-3AD4-495D-9B13-F8EC5E8F1865}.Release|Any CPU.Build.0 = Release|Any CPU
{206655CC-CFCA-4F8B-A7B1-56B299A6DCA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{206655CC-CFCA-4F8B-A7B1-56B299A6DCA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{206655CC-CFCA-4F8B-A7B1-56B299A6DCA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{206655CC-CFCA-4F8B-A7B1-56B299A6DCA0}.Release|Any CPU.Build.0 = Release|Any CPU
{BFA704DC-BB88-44EE-93C9-D2258ABD1FCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFA704DC-BB88-44EE-93C9-D2258ABD1FCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFA704DC-BB88-44EE-93C9-D2258ABD1FCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFA704DC-BB88-44EE-93C9-D2258ABD1FCD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# Kek.Net
A collection of reusable code I've found myself needing thoughout the years of my .NET work
A collection of reusable code I've found myself needing throughout the years of my .NET work.

## Packages
* [Kek.Net.ErrorHandling](docs/index.md#error-handling)
* [Kek.Net.Extensions](docs/index.md#extensions)
6 changes: 6 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Kek.Net Documentation

## Error handling
[Kek.Net.ErrorHandling](../src/Kek.Net.ErrorHandling) is inspired by Rust's `Result` type.

## Extensions
6 changes: 6 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"sdk": {
"version": "8.0.202",
"rollForward": "latestMinor"
}
}
1 change: 1 addition & 0 deletions src/Kek.Net.AspNet/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Microsoft.AspNetCore.Http;
6 changes: 6 additions & 0 deletions src/Kek.Net.AspNet/JsonResponse/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Kek.Net.AspNet.JsonResponse;

internal static class Constants
{
internal const string JsonResponseMediaType = "application/json";
}
6 changes: 6 additions & 0 deletions src/Kek.Net.AspNet/JsonResponse/IJsonDataResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Kek.Net.AspNet.JsonResponse;

public interface IJsonDataResponse<out TData>
{
public TData? Data { get; }
}
6 changes: 6 additions & 0 deletions src/Kek.Net.AspNet/JsonResponse/IJsonErrorResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Kek.Net.AspNet.JsonResponse;

public interface IJsonErrorResponse
{
public ICollection<JsonError>? Errors { get; }
}
7 changes: 7 additions & 0 deletions src/Kek.Net.AspNet/JsonResponse/JsonError.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Kek.Net.AspNet.JsonResponse;

public class JsonError
{
public string Message { get; set; } = string.Empty;
public IDictionary<string, object>? Metadata { get; set; }
}
16 changes: 16 additions & 0 deletions src/Kek.Net.AspNet/JsonResponse/JsonResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;

namespace Kek.Net.AspNet.JsonResponse;

/// <summary>
/// Response object that represents an api call returning data (or an empty response).
/// </summary>
/// <typeparam name="TData">The type of data this response contains. Can be set to <see cref="Object"/> if the response is empty.</typeparam>
public class JsonResponse<TData> : IJsonDataResponse<TData>, IJsonErrorResponse
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public TData? Data { get; }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public ICollection<JsonError>? Errors { get; }
}
35 changes: 35 additions & 0 deletions src/Kek.Net.AspNet/JsonResponse/JsonResponseAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Formatters;

namespace Kek.Net.AspNet.JsonResponse;

/// <summary>
/// This attribute informs the API explorer which status code maps to which Json Api response.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class JsonResponseAttribute: Attribute, IApiResponseMetadataProvider
{
/// <summary>
/// A typed result returning data. Status code will be 200.
/// </summary>
/// <param name="resultType">The type of the result data.</param>
public JsonResponseAttribute(Type resultType)
{
Type = typeof(IJsonDataResponse<>).MakeGenericType(resultType);
StatusCode = StatusCodes.Status200OK;
}

protected JsonResponseAttribute(int statusCode)
{
StatusCode = statusCode;
}

public void SetContentTypes(MediaTypeCollection contentTypes)
{
contentTypes.Clear();
contentTypes.Add(Constants.JsonResponseMediaType);
}

public Type? Type { get; protected set; }
public int StatusCode { get; protected set; }
}
13 changes: 13 additions & 0 deletions src/Kek.Net.AspNet/JsonResponse/JsonResponseErrorAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Kek.Net.AspNet.JsonResponse;

/// <summary>
/// Indicates that a controller action could return a <see cref="IJsonErrorResponse"/> for a certain status code.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class JsonResponseErrorAttribute : JsonResponseAttribute
{
public JsonResponseErrorAttribute(int statusCode) : base(statusCode)
{
Type = typeof(IJsonErrorResponse);
}
}
13 changes: 13 additions & 0 deletions src/Kek.Net.AspNet/Kek.Net.AspNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DocumentationFile>bin\Release\Kek.Net.AspNet.xml</DocumentationFile>
</PropertyGroup>

<ItemGroup>
Expand All @@ -12,5 +17,13 @@

<ItemGroup>
<ProjectReference Include="..\..\Kek.Net.ErrorHandling\Kek.Net.ErrorHandling.csproj" />
<ProjectReference Include="..\Kek.Net.ErrorHandling\Kek.Net.ErrorHandling.csproj" />
</ItemGroup>

<ItemGroup>
<Content Include="..\..\LICENSE">
<Link>LICENSE</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions src/Kek.Net.AspNet/version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
version:
major: 0
minor: 1
patch: 0
9 changes: 9 additions & 0 deletions src/Kek.Net.ErrorHandling/IError.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Kek.Net.ErrorHandling;

/// <summary>
/// If a reason for a <see cref="IResult"/> is the cause of a failure, it is an error.
/// </summary>
public interface IError : IReason
{

}
16 changes: 16 additions & 0 deletions src/Kek.Net.ErrorHandling/IReason.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Kek.Net.ErrorHandling;

/// <summary>
/// A reason for the <see cref="IResult"/> status.
/// </summary>
public interface IReason
{
/// <summary>
/// The message describing the reason.
/// </summary>
string Message { get; }
/// <summary>
/// Optional metadata accompanying the reason.
/// </summary>
IDictionary<string, object?> Metadata { get; }
}
20 changes: 20 additions & 0 deletions src/Kek.Net.ErrorHandling/IResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace Kek.Net.ErrorHandling;

/// <summary>
/// Interface describing a result of an operation.
/// </summary>
public interface IResult
{
/// <summary>
/// Indicates the operation is a success.
/// </summary>
bool IsSuccess { get; }
/// <summary>
/// Any errors the operation might have caused.
/// </summary>
ICollection<IError> Errors { get; }
/// <summary>
/// Any reasons for the operation result
/// </summary>
ICollection<IReason> Reasons { get; }
}
20 changes: 20 additions & 0 deletions src/Kek.Net.ErrorHandling/Kek.Net.ErrorHandling.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DocumentationFile>bin\Release\Kek.Net.ErrorHandling.xml</DocumentationFile>
</PropertyGroup>

<ItemGroup>
<Content Include="..\..\LICENSE">
<Link>LICENSE</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
14 changes: 14 additions & 0 deletions src/Kek.Net.ErrorHandling/ResultBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Kek.Net.ErrorHandling;

/// <summary>
/// Abstract implementation of <see cref="IResult"/>.
/// </summary>
public abstract class ResultBase : IResult
{
/// <inheritdoc />
public bool IsSuccess { get; protected set; }
/// <inheritdoc />
public ICollection<IError> Errors => Reasons.OfType<IError>().ToList();
/// <inheritdoc />
public ICollection<IReason> Reasons { get; } = new List<IReason>();
}
4 changes: 4 additions & 0 deletions src/Kek.Net.ErrorHandling/version.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
version:
major: 0
minor: 1
patch: 0
Loading