Skip to content

Commit

Permalink
Use our own app to create the CI Completion check
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyberboss committed Mar 3, 2024
1 parent 4c59fad commit 660b549
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 12 deletions.
35 changes: 24 additions & 11 deletions .github/workflows/ci-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1396,19 +1396,32 @@ jobs:
name: CI Completion Gate
needs: [ pages-build, docker-build, build-deb, build-msi, validate-openapi-spec, upload-code-coverage, check-winget-pr-template, code-scanning ]
runs-on: ubuntu-latest
permissions:
checks: write
contents: read
if: (!(cancelled() || failure()) && needs.pages-build.result == 'success' && needs.docker-build.result == 'success' && needs.build-deb.result == 'success' && needs.build-msi.result == 'success' && needs.validate-openapi-spec.result == 'success' && needs.upload-code-coverage.result == 'success' && needs.check-winget-pr-template.result == 'success' && needs.code-scanning.result == 'success')
steps:
- name: Create Completion Check
uses: LouisBrunner/checks-action@6b626ffbad7cc56fd58627f774b9067e6118af23
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: CI Completion
conclusion: success
output: |
{"summary":"The CI Pipeline completed successfully"}
- name: Setup dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: '${{ env.TGS_DOTNET_VERSION }}.0.x'
dotnet-quality: ${{ env.TGS_DOTNET_QUALITY }}

- name: Checkout (Branch)
uses: actions/checkout@v4
if: github.event_name == 'push' || github.event_name == 'schedule'

- name: Checkout (PR Merge)
uses: actions/checkout@v4
if: github.event_name != 'push' && github.event_name != 'schedule'
with:
ref: "refs/pull/${{ github.event.number }}/merge"

- name: Restore
run: dotnet restore

- name: Build ReleaseNotes
run: dotnet build -c Release -p:TGS_HOST_NO_WEBPANEL=true tools/Tgstation.Server.ReleaseNotes/Tgstation.Server.ReleaseNotes.csproj

- name: Run ReleaseNotes Create CI Completion Check
run: dotnet run -c Release --no-build --project tools/Tgstation.Server.ReleaseNotes --ci-completion-check ${{ github.sha }} ${{ secrets.TGS_CI_GITHUB_APP_TOKEN_BASE64 }}

deployment-gate:
name: Deployment Start Gate
Expand Down
64 changes: 63 additions & 1 deletion tools/Tgstation.Server.ReleaseNotes/Program.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
// This program is minimal effort and should be sent to remedial school

using System;
using System.Buffers.Text;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

using Microsoft.IdentityModel.Tokens;

using Newtonsoft.Json;

using Octokit;
Expand All @@ -32,8 +37,11 @@ namespace Tgstation.Server.ReleaseNotes
static class Program
{
const string OutputPath = "release_notes.md";

// some stuff that should be abstracted for different repos
const string RepoOwner = "tgstation";
const string RepoName = "tgstation-server";
const int AppId = 847638;

/// <summary>
/// The entrypoint for the <see cref="Program"/>
Expand All @@ -52,13 +60,15 @@ static async Task<int> Main(string[] args)
var shaCheck = versionString.Equals("--winget-template-check", StringComparison.OrdinalIgnoreCase);
var fullNotes = versionString.Equals("--generate-full-notes", StringComparison.OrdinalIgnoreCase);
var nuget = versionString.Equals("--nuget", StringComparison.OrdinalIgnoreCase);
var ciCompletionCheck = versionString.Equals("--ci-completion-check", StringComparison.OrdinalIgnoreCase);

if ((!Version.TryParse(versionString, out var version) || version.Revision != -1)
&& !ensureRelease
&& !linkWinget
&& !shaCheck
&& !fullNotes
&& !nuget)
&& !nuget
&& !ciCompletionCheck)
{
Console.WriteLine("Invalid version: " + versionString);
return 2;
Expand Down Expand Up @@ -129,6 +139,17 @@ static async Task<int> Main(string[] args)
return await Winget(client, actionsUrl, null);
}

if (ciCompletionCheck)
{
if (args.Length < 3)
{
Console.WriteLine("Missing SHA or PEM Base64 for creating check run!");
return 4543;
}

return await CICompletionCheck(client, args[1], args[2]);
}

if (shaCheck)
{
if(args.Length < 2)
Expand Down Expand Up @@ -1583,6 +1604,47 @@ static async Task<int> GenDebianChangelog(IGitHubClient client, Version version,
return 0;
}

static async ValueTask<int> CICompletionCheck(GitHubClient gitHubClient, string currentSha, string pemBase64)
{
var pemBytes = Convert.FromBase64String(pemBase64);
var pem = Encoding.UTF8.GetString(pemBytes);

var rsa = RSA.Create();
rsa.ImportFromPem(pem);

var signingCredentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256);
var jwtSecurityTokenHandler = new JwtSecurityTokenHandler { SetDefaultTimesOnTokenCreation = false };

var now = DateTime.UtcNow;

var jwt = jwtSecurityTokenHandler.CreateToken(new SecurityTokenDescriptor
{
Issuer = AppId.ToString(),
Expires = now.AddMinutes(10),
IssuedAt = now,
SigningCredentials = signingCredentials
});

var jwtStr = jwtSecurityTokenHandler.WriteToken(jwt);

gitHubClient.Credentials = new Credentials(jwtStr, AuthenticationType.Bearer);

var installation = await gitHubClient.GitHubApps.GetRepositoryInstallationForCurrent(RepoOwner, RepoName);
var installToken = await gitHubClient.GitHubApps.CreateInstallationToken(installation.Id);

gitHubClient.Credentials = new Credentials(installToken.Token);

await gitHubClient.Check.Run.Create(RepoOwner, RepoName, new NewCheckRun("CI Completion", currentSha)
{
CompletedAt = now,
Conclusion = CheckConclusion.Success,
Output = new NewCheckRunOutput("CI Completion", "The CI Pipeline completed successfully"),
Status = CheckStatus.Completed,
});

return 0;
}

static void DebugAssert(bool condition, string message = null)
{
// This exists because one of the fucking asserts evaluates an enumerable or something and it was getting optimized out in release
Expand Down

0 comments on commit 660b549

Please sign in to comment.