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: add initial repository #1

Merged
merged 3 commits into from
Mar 30, 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
34 changes: 34 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Build

on:
push:
branches: [main]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: Publish
run: dotnet publish -c Release --output /home/runner/work/grox.at/grox.at/publish/
- name: Upload ftp
uses: sebastianpopp/ftp-action@releases/v2
with:
host: ftps://access938340810.webspace-data.io:990
user: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
localDir: /home/runner/work/grox.at/grox.at/publish/
remoteDir: "."
options: "--delete"
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI

on:
pull_request:
branches: [ "main" ]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
176 changes: 176 additions & 0 deletions Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
using System.Net.Http.Headers;
using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Testably.Server.Controllers;

[Route("pr-status-check")]
[ApiController]
[AllowAnonymous]
public class PullRequestStatusCheckController : ControllerBase
{
private const string RepositoryOwner = "Testably";
private readonly IConfiguration _configuration;
private readonly IHttpClientFactory _clientFactory;
private readonly ILogger<PullRequestStatusCheckController> _logger;


private const string SuccessMessage =
"Title must conform to the conventional commits naming convention";

private static readonly string[] ValidTypes =
{
"fix",
"feat",
"release",

// https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional
"build",
"chore",
"ci",
"docs",
"perf",
"refactor",
"revert",
"style",
"test"
};

public PullRequestStatusCheckController(
IConfiguration configuration,
IHttpClientFactory clientFactory,
ILogger<PullRequestStatusCheckController> logger)
{
_configuration = configuration;
_clientFactory = clientFactory;
_logger = logger;
}

[HttpPost]
public async Task<IActionResult> OnPullRequestChanged(
[FromBody] WebhookModel<PullRequestWebhookModel> pullRequestModel,
CancellationToken cancellationToken)
{
if (pullRequestModel.Payload.Repository.Private ||
pullRequestModel.Payload.Repository.Owner.Login != RepositoryOwner)
{
return BadRequest($"Only public repositories from '{RepositoryOwner}' are supported!");
}

_logger.LogInformation("Received {PullRequestWebhookModel}", pullRequestModel);

using var client = _clientFactory.CreateClient();

var owner = pullRequestModel.Payload.Repository.Owner.Login;
var repo = pullRequestModel.Payload.Repository.Name;
var prNumber = pullRequestModel.Payload.Number;
var requestUri = $"https://api.github.com/repos/{owner}/{repo}/pulls/{prNumber}";
var response = await client
.GetAsync(requestUri, cancellationToken);

if (!response.IsSuccessStatusCode)
{
return StatusCode(StatusCodes.Status500InternalServerError,
$"GitHub API '{requestUri}' not available");
}

var jsonDocument = await JsonDocument.ParseAsync(
await response.Content.ReadAsStreamAsync(cancellationToken),
cancellationToken: cancellationToken);

if (!jsonDocument.RootElement.TryGetProperty("title", out var titleProperty) ||
titleProperty.GetString() == null)
{
return StatusCode(StatusCodes.Status500InternalServerError,
$"GitHub API '{requestUri}' returned an invalid response");
}

var bearerToken = _configuration.GetValue<string>("GithubBearerToken");
var title = titleProperty.GetString()!;
string commitSha = pullRequestModel.Payload.PullRequest.MergeCommitSha;
var statusUri = $"https://api.github.com/repos/{owner}/{repo}/statuses/{commitSha}";
bool hasValidTitle = ValidateTitle(title);
// https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#create-a-commit-status
var json = JsonSerializer.Serialize(new
{
context = "Testably/Conventional-Commits",
state = hasValidTitle ? "success" : "failure",
description = "The PR title must conform to the conventional commits guideline."
});
using var content = new StringContent(json);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", bearerToken);
await client.PostAsync(statusUri, content, cancellationToken);
return NoContent();
}

private bool ValidateTitle(string title)
{
foreach (var validType in ValidTypes)
{
if (!title.StartsWith(validType))
{
continue;
}

var index = title.IndexOf(':');
if (index < 0)
{
continue;
}

// Check whitespace after first colon
if (title.Substring(index + 1, 1) != " ")
{
continue;
}

var scope = title.Substring(0, index).Substring(validType.Length);
if (scope == "" || scope == "!")
{
return true;
}

if (scope.StartsWith('(') && scope.EndsWith(')'))
{
return true;
}
}

return false;
}

public class WebhookModel<T>
{
public string Event { get; set; }

Check warning on line 146 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Event' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public T Payload { get; set; }

Check warning on line 147 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Payload' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

public class PullRequestWebhookModel
{
public string Action { get; set; } = "";
public int Number { get; set; }

public PullRequestModel PullRequest { get; set; }

Check warning on line 155 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'PullRequest' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

public RepositoryModel Repository { get; set; }

Check warning on line 157 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Repository' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

public class PullRequestModel
{
public string MergeCommitSha { get; set; }

Check warning on line 162 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'MergeCommitSha' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}

public class RepositoryModel
{
public string Name { get; set; }

Check warning on line 167 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 167 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Name' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public RepositoryOwnerModel Owner { get; set; }

Check warning on line 168 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Owner' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
public bool Private { get; set; }
}

public class RepositoryOwnerModel
{
public string Login { get; set; }

Check warning on line 174 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Login' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 174 in Source/Testably.Server/Controllers/PullRequestStatusCheckController.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Login' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
}
}
26 changes: 26 additions & 0 deletions Source/Testably.Server/Pages/Error.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}

<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
26 changes: 26 additions & 0 deletions Source/Testably.Server/Pages/Error.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Testably.Server.Pages;

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

private readonly ILogger<ErrorModel> _logger;

public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}

public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
10 changes: 10 additions & 0 deletions Source/Testably.Server/Pages/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}

<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
17 changes: 17 additions & 0 deletions Source/Testably.Server/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Testably.Server.Pages;

public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;

public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}

public void OnGet()
{
}
}
8 changes: 8 additions & 0 deletions Source/Testably.Server/Pages/Privacy.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>
17 changes: 17 additions & 0 deletions Source/Testably.Server/Pages/Privacy.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace Testably.Server.Pages;

public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;

public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}

public void OnGet()
{
}
}
Loading
Loading