Merge pull request #1824 from tgstation/WowForgorTheRead [TGSDeploy]

v6.6.0: Fix cron schedule handling in API. Update Webpanel to 5.8.0
This commit is contained in:
Jordan Dominion
2024-07-06 17:46:32 -04:00
committed by GitHub
44 changed files with 8291 additions and 144 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ async function getFailedJobsForRun(github, context, workflowRunId, runAttempt) {
attempt_number: runAttempt
},
response => {
return response.data.jobs;
return response.data;
});
return jobs
+5 -1
View File
@@ -12,7 +12,11 @@ This is a toolset to manage production DreamMaker servers. It includes the abili
### Pre-Requisites
_Note: If you opt to use the Windows installer, all pre-requisites for running BYOND servers (including MariaDB) are provided out of the box. If you wish to use OpenDream you will need to install the required dotnet SDK manually._
_Note: If you opt to use the Windows installer, most pre-requisites for running BYOND servers (including MariaDB) are provided out of the box._
_If you are running on a Windows Server OS. You **might** need to install the [x86 Visual C++ 2015 Runtime](https://aka.ms/vs/17/release/vc_redist.x86.exe) to run BYOND._
_If you wish to use OpenDream you will need to install the required dotnet SDK manually._
tgstation-server needs a relational database to store it's data.
+4 -4
View File
@@ -8,19 +8,19 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- Usage: Logging specific for GitHub actions -->
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3">
<PackageReference Include="GitHubActionsTestLogger" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- Usage: Hard to say what exactly this is for, but not including it removes the test icon and breaks vstest.console.exe for some reason -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" Condition="'$(TgsTestNoSdk)' != 'true'" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" Condition="'$(TgsTestNoSdk)' != 'true'" />
<!-- Usage: Dependency mocking for tests -->
<!-- Pinned: Be VERY careful about updating https://github.com/moq/moq/issues/1372 -->
<PackageReference Include="Moq" Version="4.20.70" />
<!-- Usage: MSTest execution -->
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.4.3" />
<!-- Usage: MSTest asserts etc... -->
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.4.3" />
</ItemGroup>
</Project>
+8 -6
View File
@@ -3,12 +3,12 @@
<!-- Integration tests will ensure they match across the board -->
<Import Project="WebpanelVersion.props" />
<PropertyGroup>
<TgsCoreVersion>6.5.0</TgsCoreVersion>
<TgsCoreVersion>6.6.0</TgsCoreVersion>
<TgsConfigVersion>5.1.0</TgsConfigVersion>
<TgsApiVersion>10.3.0</TgsApiVersion>
<TgsApiVersion>10.4.0</TgsApiVersion>
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
<TgsApiLibraryVersion>13.3.0</TgsApiLibraryVersion>
<TgsClientVersion>15.3.0</TgsClientVersion>
<TgsApiLibraryVersion>13.4.0</TgsApiLibraryVersion>
<TgsClientVersion>15.4.0</TgsClientVersion>
<TgsDmapiVersion>7.1.2</TgsDmapiVersion>
<TgsInteropVersion>5.9.0</TgsInteropVersion>
<TgsHostWatchdogVersion>1.4.1</TgsHostWatchdogVersion>
@@ -17,8 +17,10 @@
<TgsNugetNetFramework>netstandard2.0</TgsNugetNetFramework>
<TgsNetMajorVersion>8</TgsNetMajorVersion>
<!-- Update this frequently with dotnet runtime patches. MAJOR MUST MATCH ABOVE! -->
<TgsDotnetRedistUrl>https://download.visualstudio.microsoft.com/download/pr/00397fee-1bd9-44ef-899b-4504b26e6e96/ab9c73409659f3238d33faee304a8b7c/dotnet-hosting-8.0.4-win.exe</TgsDotnetRedistUrl>
<TgsMariaDBRedistVersion>10.11.6</TgsMariaDBRedistVersion>
<TgsDotnetRedistUrl>https://download.visualstudio.microsoft.com/download/pr/751d3fcd-72db-4da2-b8d0-709c19442225/33cc492bde704bfd6d70a2b9109005a0/dotnet-hosting-8.0.6-win.exe</TgsDotnetRedistUrl>
<TgsMariaDBRedistVersion>10.11.8</TgsMariaDBRedistVersion>
<!-- Only have this uncommented if the mariadb servers are shitting the bed, update if the version updates -->
<TgsMariaDBFallbackRedist>https://mirror.its.dal.ca/mariadb//mariadb-10.11.8/winx64-packages/mariadb-10.11.8-winx64.msi</TgsMariaDBFallbackRedist>
<TgsYarnVersion>1.22.21</TgsYarnVersion>
</PropertyGroup>
</Project>
+1 -1
View File
@@ -1,6 +1,6 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- This is in it's own file to help incremental building, changing it causes a complete rebuild of the web panel -->
<TgsWebpanelVersion>5.7.1</TgsWebpanelVersion>
<TgsWebpanelVersion>5.8.0</TgsWebpanelVersion>
</PropertyGroup>
</Project>
@@ -35,7 +35,15 @@ try
try
{
Invoke-WebRequest -Uri $redistUrl -OutFile artifacts/hosting-bundle.exe
Invoke-WebRequest -Uri $dbRedistUrl -OutFile artifacts/mariadb.msi
try
{
Invoke-WebRequest -Uri $dbRedistUrl -OutFile artifacts/mariadb.msi
}
catch
{
$dbRedistUrl = $versionXML.Project.PropertyGroup.TgsMariaDBFallbackRedist
Invoke-WebRequest -Uri $dbRedistUrl -OutFile artifacts/mariadb.msi
}
} finally {
$ProgressPreference = $previousProgressPreference
}
@@ -31,9 +31,18 @@ namespace Tgstation.Server.Api.Models
/// <summary>
/// The time interval in minutes the repository is automatically pulled and compiles. 0 disables.
/// </summary>
/// <remarks>Auto-updates intervals start counting when set, TGS is started, or from the completion of the previous update. Incompatible with <see cref="AutoUpdateCron"/>.</remarks>
[Required]
public uint? AutoUpdateInterval { get; set; }
/// <summary>
/// A cron expression indicating when auto-updates should trigger. Must be a valid 6 part cron schedule (SECONDS MINUTES HOURS DAY/MONTH MONTH DAY/WEEK). Empty <see cref="string"/> disables.
/// </summary>
/// <remarks>Updates will not be triggered if the previous update is still running. Incompatible with <see cref="AutoUpdateInterval"/>.</remarks>
[Required]
[StringLength(Limits.MaximumStringLength)]
public string? AutoUpdateCron { get; set; }
/// <summary>
/// The maximum number of chat bots the <see cref="Instance"/> may contain.
/// </summary>
@@ -27,7 +27,7 @@
<!-- Usage: HTTP constants reference -->
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
<!-- Usage: Decoding the 'nbf' property of JWTs -->
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.5.1" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.6.2" />
<!-- Usage: Primary JSON library -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<!-- Usage: Data model annotating -->
@@ -11,9 +11,9 @@
<ItemGroup>
<!-- Usage: Connecting to SignalR hubs in API -->
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.6" />
<!-- Usage: Using target JSON serializer for API -->
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.6" />
</ItemGroup>
<ItemGroup>
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "8.0.4",
"version": "8.0.6",
"commands": [
"dotnet-ef"
]
@@ -45,10 +45,11 @@ namespace Tgstation.Server.Host.Components
IConfiguration Configuration { get; }
/// <summary>
/// Change the <see cref="Api.Models.Instance.AutoUpdateInterval"/> for the <see cref="IInstanceCore"/>.
/// Change the auto-update timing for the <see cref="IInstanceCore"/>.
/// </summary>
/// <param name="newInterval">The new auto update inteval.</param>
/// <param name="newInterval">The new auto-update inteval.</param>
/// <param name="newCron">The new auto-update cron schedule.</param>
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
ValueTask SetAutoUpdateInterval(uint newInterval);
ValueTask ScheduleAutoUpdate(uint newInterval, string? newCron);
}
}
+111 -60
View File
@@ -1,11 +1,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NCrontab;
using Serilog.Context;
using Tgstation.Server.Api.Rights;
@@ -183,7 +187,7 @@ namespace Tgstation.Server.Host.Components
using (LogContext.PushProperty(SerilogContextHelper.InstanceIdContextProperty, metadata.Id))
{
await Task.WhenAll(
SetAutoUpdateInterval(metadata.Require(x => x.AutoUpdateInterval)).AsTask(),
ScheduleAutoUpdate(metadata.Require(x => x.AutoUpdateInterval), metadata.AutoUpdateCron).AsTask(),
Configuration.StartAsync(cancellationToken),
EngineManager.StartAsync(cancellationToken),
Chat.StartAsync(cancellationToken),
@@ -202,7 +206,7 @@ namespace Tgstation.Server.Host.Components
using (LogContext.PushProperty(SerilogContextHelper.InstanceIdContextProperty, metadata.Id))
{
logger.LogDebug("Stopping instance...");
await SetAutoUpdateInterval(0);
await ScheduleAutoUpdate(0, null);
await Watchdog.StopAsync(cancellationToken);
await Task.WhenAll(
Configuration.StopAsync(cancellationToken),
@@ -213,11 +217,13 @@ namespace Tgstation.Server.Host.Components
}
/// <inheritdoc />
public async ValueTask SetAutoUpdateInterval(uint newInterval)
public async ValueTask ScheduleAutoUpdate(uint newInterval, string? newCron)
{
if (newInterval > 0 && !String.IsNullOrWhiteSpace(newCron))
throw new ArgumentException("Only one of newInterval and newCron may be set!");
Task toWait;
lock (timerLock)
{
if (timerTask != null)
{
logger.LogTrace("Cancelling auto-update task");
@@ -229,12 +235,11 @@ namespace Tgstation.Server.Host.Components
}
else
toWait = Task.CompletedTask;
}
await toWait;
if (newInterval == 0)
if (newInterval == 0 && String.IsNullOrWhiteSpace(newCron))
{
logger.LogTrace("New auto-update interval is 0. Not starting task.");
logger.LogTrace("Auto-update disabled 0. Not starting task.");
return;
}
@@ -243,12 +248,12 @@ namespace Tgstation.Server.Host.Components
// race condition, just quit
if (timerTask != null)
{
logger.LogWarning("Aborting auto update interval change due to race condition!");
logger.LogWarning("Aborting auto-update scheduling change due to race condition!");
return;
}
timerCts = new CancellationTokenSource();
timerTask = TimerLoop(newInterval, timerCts.Token);
timerTask = TimerLoop(newInterval, newCron, timerCts.Token);
}
}
@@ -484,82 +489,128 @@ namespace Tgstation.Server.Host.Components
/// Pull the repository and compile for every set of given <paramref name="minutes"/>.
/// </summary>
/// <param name="minutes">How many minutes the operation should repeat. Does not include running time.</param>
/// <param name="cron">Alternative cron schedule.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
#pragma warning disable CA1502 // TODO: Decomplexify
async Task TimerLoop(uint minutes, CancellationToken cancellationToken)
async Task TimerLoop(uint minutes, string? cron, CancellationToken cancellationToken)
{
logger.LogDebug("Entering auto-update loop");
while (true)
try
{
await asyncDelayer.Delay(TimeSpan.FromMinutes(minutes > Int32.MaxValue ? Int32.MaxValue : minutes), cancellationToken);
TimeSpan delay;
if (!String.IsNullOrWhiteSpace(cron))
{
logger.LogTrace("Using cron schedule: {cron}", cron);
var schedule = CrontabSchedule.Parse(
cron,
new CrontabSchedule.ParseOptions
{
IncludingSeconds = true,
});
var now = DateTime.UtcNow;
var nextOccurrence = schedule.GetNextOccurrence(now);
delay = nextOccurrence - now;
}
else
{
logger.LogTrace("Using interval: {interval}m", minutes);
delay = TimeSpan.FromMinutes(minutes);
}
logger.LogInformation("Next auto-update will occur at {time}", DateTimeOffset.UtcNow + delay);
// https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.delay?view=net-8.0#system-threading-tasks-task-delay(system-timespan)
const uint DelayMinutesLimit = UInt32.MaxValue - 1;
Debug.Assert(DelayMinutesLimit == 4294967294, "Delay limit assertion failure!");
var maxDelayIterations = 0UL;
if (delay.TotalMilliseconds >= UInt32.MaxValue)
{
maxDelayIterations = (ulong)Math.Floor(delay.TotalMilliseconds / DelayMinutesLimit);
logger.LogDebug("Breaking interval into {iterationCount} iterations", maxDelayIterations + 1);
delay = TimeSpan.FromMilliseconds(delay.TotalMilliseconds - (maxDelayIterations * DelayMinutesLimit));
}
if (maxDelayIterations > 0)
{
var longDelayTimeSpan = TimeSpan.FromMilliseconds(DelayMinutesLimit);
for (var i = 0UL; i < maxDelayIterations; ++i)
{
logger.LogTrace("Long delay #{iteration}...", i + 1);
await asyncDelayer.Delay(longDelayTimeSpan, cancellationToken);
}
logger.LogTrace("Final delay iteration #{iteration}...", maxDelayIterations + 1);
}
await asyncDelayer.Delay(delay, cancellationToken);
logger.LogInformation("Beginning auto update...");
await eventConsumer.HandleEvent(EventType.InstanceAutoUpdateStart, Enumerable.Empty<string>(), true, cancellationToken);
try
{
var repositoryUpdateJob = Job.Create(Api.Models.JobCode.RepositoryAutoUpdate, null, metadata, RepositoryRights.CancelPendingChanges);
await jobManager.RegisterOperation(
repositoryUpdateJob,
RepositoryAutoUpdateJob,
cancellationToken);
var repoUpdateJobResult = await jobManager.WaitForJobCompletion(repositoryUpdateJob, null, cancellationToken, cancellationToken);
if (repoUpdateJobResult == false)
var repositoryUpdateJob = Job.Create(Api.Models.JobCode.RepositoryAutoUpdate, null, metadata, RepositoryRights.CancelPendingChanges);
await jobManager.RegisterOperation(
repositoryUpdateJob,
RepositoryAutoUpdateJob,
cancellationToken);
var repoUpdateJobResult = await jobManager.WaitForJobCompletion(repositoryUpdateJob, null, cancellationToken, cancellationToken);
if (repoUpdateJobResult == false)
{
logger.LogWarning("Aborting auto-update due to repository update error!");
continue;
}
Job compileProcessJob;
using (var repo = await RepositoryManager.LoadRepository(cancellationToken))
{
if (repo == null)
throw new JobException(Api.Models.ErrorCode.RepoMissing);
var deploySha = repo.Head;
if (deploySha == null)
{
logger.LogWarning("Aborting auto-update due to repository update error!");
logger.LogTrace("Aborting auto update, repository error!");
continue;
}
Job compileProcessJob;
using (var repo = await RepositoryManager.LoadRepository(cancellationToken))
if (deploySha == LatestCompileJob()?.RevisionInformation.CommitSha)
{
if (repo == null)
throw new JobException(Api.Models.ErrorCode.RepoMissing);
var deploySha = repo.Head;
if (deploySha == null)
{
logger.LogTrace("Aborting auto update, repository error!");
continue;
}
if (deploySha == LatestCompileJob()?.RevisionInformation.CommitSha)
{
logger.LogTrace("Aborting auto update, same revision as latest CompileJob");
continue;
}
// finally set up the job
compileProcessJob = Job.Create(Api.Models.JobCode.AutomaticDeployment, null, metadata, DreamMakerRights.CancelCompile);
await jobManager.RegisterOperation(
compileProcessJob,
(core, databaseContextFactory, job, progressReporter, jobCancellationToken) =>
{
if (core != this)
throw new InvalidOperationException(DifferentCoreExceptionMessage);
return DreamMaker.DeploymentProcess(
job,
databaseContextFactory,
progressReporter,
jobCancellationToken);
},
cancellationToken);
logger.LogTrace("Aborting auto update, same revision as latest CompileJob");
continue;
}
await jobManager.WaitForJobCompletion(compileProcessJob, null, default, cancellationToken);
}
catch (Exception e) when (e is not OperationCanceledException)
{
logger.LogWarning(e, "Error in auto update loop!");
continue;
// finally set up the job
compileProcessJob = Job.Create(Api.Models.JobCode.AutomaticDeployment, null, metadata, DreamMakerRights.CancelCompile);
await jobManager.RegisterOperation(
compileProcessJob,
(core, databaseContextFactory, job, progressReporter, jobCancellationToken) =>
{
if (core != this)
throw new InvalidOperationException(DifferentCoreExceptionMessage);
return DreamMaker.DeploymentProcess(
job,
databaseContextFactory,
progressReporter,
jobCancellationToken);
},
cancellationToken);
}
await jobManager.WaitForJobCompletion(compileProcessJob, null, default, cancellationToken);
}
catch (OperationCanceledException)
{
logger.LogDebug("Cancelled auto update loop!");
break;
}
catch (Exception e)
{
logger.LogError(e, "Error in auto update loop!");
continue;
}
logger.LogTrace("Leaving auto update loop...");
}
@@ -55,7 +55,7 @@ namespace Tgstation.Server.Host.Components
public ValueTask InstanceRenamed(string newInstanceName, CancellationToken cancellationToken) => Instance.InstanceRenamed(newInstanceName, cancellationToken);
/// <inheritdoc />
public ValueTask SetAutoUpdateInterval(uint newInterval) => Instance.SetAutoUpdateInterval(newInterval);
public ValueTask ScheduleAutoUpdate(uint newInterval, string? newCron) => Instance.ScheduleAutoUpdate(newInterval, newCron);
/// <inheritdoc />
public CompileJob? LatestCompileJob() => Instance.LatestCompileJob();
@@ -13,6 +13,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NCrontab;
using Tgstation.Server.Api;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Api.Models.Request;
@@ -144,6 +146,10 @@ namespace Tgstation.Server.Host.Controllers
if (String.IsNullOrWhiteSpace(model.Name) || String.IsNullOrWhiteSpace(model.Path))
return BadRequest(new ErrorMessageResponse(ErrorCode.InstanceWhitespaceNameOrPath));
IActionResult? earlyOut = ValidateCronSetting(model);
if (earlyOut != null)
return earlyOut;
var unNormalizedPath = model.Path;
var targetInstancePath = NormalizePath(unNormalizedPath);
model.Path = targetInstancePath;
@@ -166,7 +172,6 @@ namespace Tgstation.Server.Host.Controllers
return Conflict(new ErrorMessageResponse(ErrorCode.InstanceAtConflictingPath));
// Validate it's not a child of any other instance
IActionResult? earlyOut = null;
ulong countOfOtherInstances = 0;
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
@@ -415,9 +420,19 @@ namespace Tgstation.Server.Host.Controllers
}
var oldAutoUpdateInterval = originalModel.AutoUpdateInterval!.Value;
var oldAutoUpdateCron = originalModel.AutoUpdateCron;
var earlyOut = ValidateCronSetting(model);
if (earlyOut != null)
return earlyOut;
var changedAutoInterval = model.AutoUpdateInterval.HasValue && oldAutoUpdateInterval != model.AutoUpdateInterval;
var changedAutoCron = model.AutoUpdateCron != null && oldAutoUpdateCron != model.AutoUpdateCron;
var renamed = model.Name != null && originalModel.Name != model.Name;
if (CheckModified(x => x.AutoUpdateInterval, InstanceManagerRights.SetAutoUpdate)
|| CheckModified(x => x.AutoUpdateCron, InstanceManagerRights.SetAutoUpdate)
|| CheckModified(x => x.ConfigurationType, InstanceManagerRights.SetConfiguration)
|| CheckModified(x => x.Name, InstanceManagerRights.Rename)
|| CheckModified(x => x.Online, InstanceManagerRights.SetOnline)
@@ -436,6 +451,11 @@ namespace Tgstation.Server.Host.Controllers
return Conflict(new ErrorMessageResponse(ErrorCode.ChatBotMax));
}
if (changedAutoCron)
model.AutoUpdateInterval = 0;
else if (changedAutoInterval)
model.AutoUpdateCron = String.Empty;
await DatabaseContext.Save(cancellationToken);
if (renamed)
@@ -497,13 +517,13 @@ namespace Tgstation.Server.Host.Controllers
api.MoveJob = job.ToApi();
}
if (model.AutoUpdateInterval.HasValue && oldAutoUpdateInterval != model.AutoUpdateInterval)
if (changedAutoInterval || changedAutoCron)
{
// ignoring retval because we don't care if it's offline
await WithComponentInstanceNullable(
async componentInstance =>
{
await componentInstance.SetAutoUpdateInterval(model.AutoUpdateInterval.Value);
await componentInstance.ScheduleAutoUpdate(model.AutoUpdateInterval!.Value, model.AutoUpdateCron);
return null;
},
originalModel);
@@ -746,6 +766,7 @@ namespace Tgstation.Server.Host.Controllers
Online = false,
Path = initialSettings.Path,
AutoUpdateInterval = initialSettings.AutoUpdateInterval ?? 0,
AutoUpdateCron = initialSettings.AutoUpdateCron ?? String.Empty,
ChatBotLimit = initialSettings.ChatBotLimit ?? Models.Instance.DefaultChatBotLimit,
RepositorySettings = new RepositorySettings
{
@@ -821,5 +842,31 @@ namespace Tgstation.Server.Host.Controllers
.Where(x => x.InstanceId == instanceResponse.Id && x.PermissionSetId == AuthenticationContext.PermissionSet.Id)
.AnyAsync(cancellationToken);
}
/// <summary>
/// Validates a given <paramref name="instance"/>'s <see cref="Api.Models.Instance.AutoUpdateCron"/> setting.
/// </summary>
/// <param name="instance">The <see cref="Api.Models.Instance"/> to validate.</param>
/// <returns><see langword="null"/> if <paramref name="instance"/> has a valid <see cref="Api.Models.Instance.AutoUpdateCron"/> setting, a <see cref="BadRequestObjectResult"/> otherwise.</returns>
BadRequestObjectResult? ValidateCronSetting(Api.Models.Instance instance)
{
if (!String.IsNullOrWhiteSpace(instance.AutoUpdateCron))
{
if ((instance.AutoUpdateInterval.HasValue && instance.AutoUpdateInterval.Value != 0)
|| (CrontabSchedule.TryParse(
instance.AutoUpdateCron,
new CrontabSchedule.ParseOptions
{
IncludingSeconds = true,
}) == null))
return BadRequest(new ErrorMessageResponse(ErrorCode.ModelValidationFailure));
instance.AutoUpdateInterval = 0;
}
else
instance.AutoUpdateCron = String.Empty;
return null;
}
}
}
@@ -375,22 +375,22 @@ namespace Tgstation.Server.Host.Database
/// <summary>
/// Used by unit tests to remind us to setup the correct MSSQL migration downgrades.
/// </summary>
internal static readonly Type MSLatestMigration = typeof(MSAddCompilerAdditionalArguments);
internal static readonly Type MSLatestMigration = typeof(MSAddCronAutoUpdates);
/// <summary>
/// Used by unit tests to remind us to setup the correct MYSQL migration downgrades.
/// </summary>
internal static readonly Type MYLatestMigration = typeof(MYAddCompilerAdditionalArguments);
internal static readonly Type MYLatestMigration = typeof(MYAddCronAutoUpdates);
/// <summary>
/// Used by unit tests to remind us to setup the correct PostgresSQL migration downgrades.
/// </summary>
internal static readonly Type PGLatestMigration = typeof(PGAddCompilerAdditionalArguments);
internal static readonly Type PGLatestMigration = typeof(PGAddCronAutoUpdates);
/// <summary>
/// Used by unit tests to remind us to setup the correct SQLite migration downgrades.
/// </summary>
internal static readonly Type SLLatestMigration = typeof(SLAddCompilerAdditionalArguments);
internal static readonly Type SLLatestMigration = typeof(SLAddCronAutoUpdates);
/// <inheritdoc />
#pragma warning disable CA1502 // Cyclomatic complexity
@@ -419,6 +419,16 @@ namespace Tgstation.Server.Host.Database
string BadDatabaseType() => throw new ArgumentException($"Invalid DatabaseType: {currentDatabaseType}", nameof(currentDatabaseType));
if (targetVersion < new Version(6, 6, 0))
targetMigration = currentDatabaseType switch
{
DatabaseType.MySql => nameof(MYAddCompilerAdditionalArguments),
DatabaseType.PostgresSql => nameof(PGAddCompilerAdditionalArguments),
DatabaseType.SqlServer => nameof(MSAddCompilerAdditionalArguments),
DatabaseType.Sqlite => nameof(SLAddCompilerAdditionalArguments),
_ => BadDatabaseType(),
};
if (targetVersion < new Version(6, 5, 0))
targetMigration = currentDatabaseType switch
{
@@ -0,0 +1,40 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class MSSwitchTo64BitDeploymentIds : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AlterColumn<long>(
name: "GitHubDeploymentId",
table: "CompileJobs",
type: "bigint",
nullable: true,
oldClrType: typeof(int),
oldType: "int",
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AlterColumn<int>(
name: "GitHubDeploymentId",
table: "CompileJobs",
type: "int",
nullable: true,
oldClrType: typeof(long),
oldType: "bigint",
oldNullable: true);
}
}
}
@@ -0,0 +1,40 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class MYSwitchTo64BitDeploymentIds : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AlterColumn<long>(
name: "GitHubDeploymentId",
table: "CompileJobs",
type: "bigint",
nullable: true,
oldClrType: typeof(int),
oldType: "int",
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AlterColumn<int>(
name: "GitHubDeploymentId",
table: "CompileJobs",
type: "int",
nullable: true,
oldClrType: typeof(long),
oldType: "bigint",
oldNullable: true);
}
}
}
@@ -0,0 +1,40 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class PGSwitchTo64BitDeploymentIds : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AlterColumn<long>(
name: "GitHubDeploymentId",
table: "CompileJobs",
type: "bigint",
nullable: true,
oldClrType: typeof(int),
oldType: "integer",
oldNullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AlterColumn<int>(
name: "GitHubDeploymentId",
table: "CompileJobs",
type: "integer",
nullable: true,
oldClrType: typeof(long),
oldType: "bigint",
oldNullable: true);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class MSAddCronAutoUpdates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "AutoUpdateCron",
table: "Instances",
type: "nvarchar(max)",
maxLength: 10000,
nullable: false,
defaultValue: String.Empty);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "AutoUpdateCron",
table: "Instances");
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,35 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class MYAddCronAutoUpdates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "AutoUpdateCron",
table: "Instances",
type: "varchar(10000)",
maxLength: 10000,
nullable: false,
defaultValue: String.Empty)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "AutoUpdateCron",
table: "Instances");
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class PGAddCronAutoUpdates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "AutoUpdateCron",
table: "Instances",
type: "character varying(10000)",
maxLength: 10000,
nullable: false,
defaultValue: String.Empty);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "AutoUpdateCron",
table: "Instances");
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tgstation.Server.Host.Database.Migrations
{
/// <inheritdoc />
public partial class SLAddCronAutoUpdates : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.AddColumn<string>(
name: "AutoUpdateCron",
table: "Instances",
type: "TEXT",
maxLength: 10000,
nullable: false,
defaultValue: String.Empty);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
ArgumentNullException.ThrowIfNull(migrationBuilder);
migrationBuilder.DropColumn(
name: "AutoUpdateCron",
table: "Instances");
}
}
}
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.4")
.HasAnnotation("ProductVersion", "8.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
@@ -149,8 +149,8 @@ namespace Tgstation.Server.Host.Database.Migrations
MySqlPropertyBuilderExtensions.HasCharSet(b.Property<string>("EngineVersion"), "utf8mb4");
b.Property<int?>("GitHubDeploymentId")
.HasColumnType("int");
b.Property<long?>("GitHubDeploymentId")
.HasColumnType("bigint");
b.Property<long?>("GitHubRepoId")
.HasColumnType("bigint");
@@ -315,6 +315,11 @@ namespace Tgstation.Server.Host.Database.Migrations
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long?>("Id"));
b.Property<string>("AutoUpdateCron")
.IsRequired()
.HasMaxLength(10000)
.HasColumnType("varchar(10000)");
b.Property<uint?>("AutoUpdateInterval")
.IsRequired()
.HasColumnType("int unsigned");
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.4")
.HasAnnotation("ProductVersion", "8.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -137,8 +137,8 @@ namespace Tgstation.Server.Host.Database.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<int?>("GitHubDeploymentId")
.HasColumnType("integer");
b.Property<long?>("GitHubDeploymentId")
.HasColumnType("bigint");
b.Property<long?>("GitHubRepoId")
.HasColumnType("bigint");
@@ -289,6 +289,11 @@ namespace Tgstation.Server.Host.Database.Migrations
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long?>("Id"));
b.Property<string>("AutoUpdateCron")
.IsRequired()
.HasMaxLength(10000)
.HasColumnType("character varying(10000)");
b.Property<long>("AutoUpdateInterval")
.HasColumnType("bigint");
@@ -13,7 +13,7 @@ namespace Tgstation.Server.Host.Database.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.4")
.HasAnnotation("ProductVersion", "8.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
@@ -139,8 +139,8 @@ namespace Tgstation.Server.Host.Database.Migrations
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<int?>("GitHubDeploymentId")
.HasColumnType("int");
b.Property<long?>("GitHubDeploymentId")
.HasColumnType("bigint");
b.Property<long?>("GitHubRepoId")
.HasColumnType("bigint");
@@ -291,6 +291,11 @@ namespace Tgstation.Server.Host.Database.Migrations
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long?>("Id"));
b.Property<string>("AutoUpdateCron")
.IsRequired()
.HasMaxLength(10000)
.HasColumnType("nvarchar(max)");
b.Property<long>("AutoUpdateInterval")
.HasColumnType("bigint");
@@ -12,7 +12,7 @@ namespace Tgstation.Server.Host.Database.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.4");
modelBuilder.HasAnnotation("ProductVersion", "8.0.6");
modelBuilder.Entity("Tgstation.Server.Host.Models.ChatBot", b =>
{
@@ -129,7 +129,7 @@ namespace Tgstation.Server.Host.Database.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<int?>("GitHubDeploymentId")
b.Property<long?>("GitHubDeploymentId")
.HasColumnType("INTEGER");
b.Property<long?>("GitHubRepoId")
@@ -281,6 +281,11 @@ namespace Tgstation.Server.Host.Database.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("AutoUpdateCron")
.IsRequired()
.HasMaxLength(10000)
.HasColumnType("TEXT");
b.Property<uint?>("AutoUpdateInterval")
.IsRequired()
.HasColumnType("INTEGER");
@@ -60,7 +60,7 @@ namespace Tgstation.Server.Host.Models
/// <summary>
/// The GitHub deployment ID associated with the <see cref="CompileJob"/> if any.
/// </summary>
public int? GitHubDeploymentId { get; set; }
public long? GitHubDeploymentId { get; set; }
/// <inheritdoc />
public override Version? DMApiVersion
@@ -69,6 +69,7 @@ namespace Tgstation.Server.Host.Models
public InstanceResponse ToApi() => new()
{
AutoUpdateInterval = AutoUpdateInterval,
AutoUpdateCron = AutoUpdateCron,
ConfigurationType = ConfigurationType,
Id = Id,
Name = Name,
@@ -70,57 +70,58 @@
<!-- Usage: IRC interop -->
<PackageReference Include="Cyberboss.SmartIrc4net.Standard" Version="0.4.7" />
<!-- Usage: .env file parsing -->
<PackageReference Include="DotEnv.Core" Version="3.0.0" />
<PackageReference Include="DotEnv.Core" Version="3.1.0" />
<!-- Usage: Text formatter for Elasticsearch logging plugin -->
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.11.0" />
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.11.1" />
<!-- Usage: GitLab interop -->
<PackageReference Include="GitLabApiClient" Version="1.8.0" />
<!-- Usage: git interop -->
<PackageReference Include="LibGit2Sharp" Version="0.30.0" />
<!-- Usage: JWT injection into HTTP pipeline -->
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6" />
<!-- Usage: Support ""legacy"" Newotonsoft.Json in HTTP pipeline. The rest of our codebase uses Newtonsoft. -->
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
<!-- Usage: Using target JSON serializer for API -->
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.4" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.6" />
<!-- Usage: Generating dumps of dotnet engine processes -->
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.510501" />
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.532401" />
<!-- Usage: Database ORM -->
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
<!-- Usage: Automatic migration generation using command line -->
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.4">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.6">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- Usage: Sqlite ORM plugin -->
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.6" />
<!-- Usage: MSSQL ORM plugin -->
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.6" />
<!-- Usage: POSIX support for syscalls, signals, and symlinks -->
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="NCrontab.Signed" Version="3.3.3" />
<!-- Usage: YAML config plugin -->
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<!-- Usage: PostgresSQL ORM plugin -->
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.2" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
<!-- Usage: GitHub.com interop -->
<PackageReference Include="Octokit" Version="11.0.1" />
<PackageReference Include="Octokit" Version="13.0.0" />
<!-- Usage: MYSQL/MariaDB ORM plugin -->
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
<!-- Usage: Discord interop -->
<PackageReference Include="Remora.Discord" Version="2024.1.0" />
<PackageReference Include="Remora.Discord" Version="2024.2.0" />
<!-- Usage: Rich logger builder -->
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<!-- Usage: Async logging plugin -->
<PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="2.0.0" />
<!-- Usage: Console logging plugin -->
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<!-- Usage: Elasticsearch logging plugin -->
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" />
<!-- Usage: File logging plugin -->
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<!-- Usage: OpenAPI spec generator -->
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<!-- Usage: Newtonsoft.Json plugin for OpenAPI spec generator -->
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.6.2" />
<!-- Usage: Windows authentication plugin allowing searching for users by name -->
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.0" />
<!-- Usage: Identifying owning user of Windows Process objects -->
@@ -128,7 +129,7 @@
<!-- Usage: Temporary resolution to compatibility issues with EFCore 7 and .NET 8 -->
<PackageReference Include="System.Security.Permissions" Version="8.0.0" />
<!-- Usage: .DeleteAsync() support for IQueryable<T>s -->
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="8.102.2.2" />
<PackageReference Include="Z.EntityFramework.Plus.EFCore" Version="8.103.0" />
</ItemGroup>
<ItemGroup>
@@ -133,7 +133,7 @@ namespace Tgstation.Server.Host.Utils.GitHub
}
/// <inheritdoc />
public async ValueTask<int> GetCurrentUserId(CancellationToken cancellationToken)
public async ValueTask<long> GetCurrentUserId(CancellationToken cancellationToken)
{
logger.LogTrace("CreateOAuthAccessToken");
@@ -183,7 +183,7 @@ namespace Tgstation.Server.Host.Utils.GitHub
}
/// <inheritdoc />
public async ValueTask<int> CreateDeployment(NewDeployment newDeployment, string repoOwner, string repoName, CancellationToken cancellationToken)
public async ValueTask<long> CreateDeployment(NewDeployment newDeployment, string repoOwner, string repoName, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(newDeployment);
@@ -206,7 +206,7 @@ namespace Tgstation.Server.Host.Utils.GitHub
}
/// <inheritdoc />
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, string repoOwner, string repoName, int deploymentId, CancellationToken cancellationToken)
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, string repoOwner, string repoName, long deploymentId, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(newDeploymentStatus);
@@ -228,7 +228,7 @@ namespace Tgstation.Server.Host.Utils.GitHub
}
/// <inheritdoc />
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, long repoId, int deploymentId, CancellationToken cancellationToken)
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, long repoId, long deploymentId, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(newDeploymentStatus);
@@ -29,7 +29,7 @@ namespace Tgstation.Server.Host.Utils.GitHub
/// <param name="repoName">The name of the target repository.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the new deployment's ID.</returns>
ValueTask<int> CreateDeployment(NewDeployment newDeployment, string repoOwner, string repoName, CancellationToken cancellationToken);
ValueTask<long> CreateDeployment(NewDeployment newDeployment, string repoOwner, string repoName, CancellationToken cancellationToken);
/// <summary>
/// Create a <paramref name="newDeploymentStatus"/> on a target deployment.
@@ -40,7 +40,7 @@ namespace Tgstation.Server.Host.Utils.GitHub
/// <param name="deploymentId">The ID of the parent deployment.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, string repoOwner, string repoName, int deploymentId, CancellationToken cancellationToken);
Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, string repoOwner, string repoName, long deploymentId, CancellationToken cancellationToken);
/// <summary>
/// Create a <paramref name="newDeploymentStatus"/> on a target deployment.
@@ -50,6 +50,6 @@ namespace Tgstation.Server.Host.Utils.GitHub
/// <param name="deploymentId">The ID of the parent deployment.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, long repoId, int deploymentId, CancellationToken cancellationToken);
Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, long repoId, long deploymentId, CancellationToken cancellationToken);
}
}
@@ -52,7 +52,7 @@ namespace Tgstation.Server.Host.Utils.GitHub
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the current user's ID.</returns>
ValueTask<int> GetCurrentUserId(CancellationToken cancellationToken);
ValueTask<long> GetCurrentUserId(CancellationToken cancellationToken);
/// <summary>
/// Get a given <paramref name="pullRequestNumber"/>.
@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.6" />
</ItemGroup>
<ItemGroup>
@@ -162,13 +162,42 @@ namespace Tgstation.Server.Tests.Live
Assert.AreEqual(ConfigurationType.HostWrite, firstTest.ConfigurationType);
Assert.IsTrue(Directory.Exists(firstTest.Path));
// a couple data validation checks
// check setting both fails
await ApiAssert.ThrowsException<ApiConflictException, InstanceResponse>(() => instanceManagerClient.Update(new InstanceUpdateRequest
{
Id = firstTest.Id,
AutoUpdateInterval = 9999,
AutoUpdateCron = "0 0 0 1 1 *"
}, cancellationToken), ErrorCode.ModelValidationFailure);
// check bad crons fail
await ApiAssert.ThrowsException<ApiConflictException, InstanceResponse>(() => instanceManagerClient.Update(new InstanceUpdateRequest
{
Id = firstTest.Id,
AutoUpdateCron = "not a cron"
}, cancellationToken), ErrorCode.ModelValidationFailure);
// regression check
await instanceManagerClient.Update(new InstanceUpdateRequest
var updated = await instanceManagerClient.Update(new InstanceUpdateRequest
{
Id = firstTest.Id,
AutoUpdateInterval = 9999,
}, cancellationToken);
Assert.AreEqual(String.Empty, updated.AutoUpdateCron);
Assert.AreEqual(9999U, updated.AutoUpdateInterval);
// check regular 6-part crons succeed
updated = await instanceManagerClient.Update(new InstanceUpdateRequest
{
Id = firstTest.Id,
AutoUpdateCron = "0 0 0 1 1 *"
}, cancellationToken);
Assert.AreEqual("0 0 0 1 1 *", updated.AutoUpdateCron);
Assert.AreEqual(0U, updated.AutoUpdateInterval);
//can't move online instance
await ApiAssert.ThrowsException<ConflictException, InstanceResponse>(() => instanceManagerClient.Update(new InstanceUpdateRequest
{
@@ -89,19 +89,19 @@ namespace Tgstation.Server.Tests.Live
return Task.CompletedTask;
}
public ValueTask<int> CreateDeployment(NewDeployment newDeployment, string repoOwner, string repoName, CancellationToken cancellationToken)
public ValueTask<long> CreateDeployment(NewDeployment newDeployment, string repoOwner, string repoName, CancellationToken cancellationToken)
{
logger.LogTrace("CreateDeployment");
return ValueTask.FromResult(new Random().Next()); ;
return ValueTask.FromResult<long>(new Random().Next()); ;
}
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, string repoOwner, string repoName, int deploymentId, CancellationToken cancellationToken)
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, string repoOwner, string repoName, long deploymentId, CancellationToken cancellationToken)
{
logger.LogTrace("CreateDeploymentStatus");
return Task.CompletedTask;
}
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, long repoId, int deploymentId, CancellationToken cancellationToken)
public Task CreateDeploymentStatus(NewDeploymentStatus newDeploymentStatus, long repoId, long deploymentId, CancellationToken cancellationToken)
{
logger.LogTrace("CreateDeploymentStatus");
return Task.CompletedTask;
@@ -113,10 +113,10 @@ namespace Tgstation.Server.Tests.Live
return ValueTask.FromResult(cryptographySuite.GetSecureString());
}
public ValueTask<int> GetCurrentUserId(CancellationToken cancellationToken)
public ValueTask<long> GetCurrentUserId(CancellationToken cancellationToken)
{
logger.LogTrace("GetCurrentUserId");
return ValueTask.FromResult(new Random().Next());
return ValueTask.FromResult<long>(new Random().Next());
}
public ValueTask<long> GetRepositoryId(string repoOwner, string repoName, CancellationToken cancellationToken)
@@ -104,6 +104,7 @@ namespace Tgstation.Server.Tests
var instance = new Host.Models.Instance
{
AutoUpdateInterval = 0,
AutoUpdateCron = String.Empty,
ChatBotLimit = 1,
ChatSettings = new List<Host.Models.ChatBot>(),
ConfigurationType = ConfigurationType.HostWrite,
+12 -8
View File
@@ -809,26 +809,30 @@ namespace Tgstation.Server.ReleaseNotes
var versionsPropertyGroup = project.Elements().First(x => x.Name == xmlNamespace + "PropertyGroup");
var coreVersion = Version.Parse(versionsPropertyGroup.Element(xmlNamespace + "TgsCoreVersion").Value);
const string BodyForPRSha = "b64a9a24ec6b13c819b47304625a88864c3872e0";
const string BodyForPRSha = "5ffc3ff5901db66d782aa0e8ed2a74b16f896091";
var prBody = $@"# Automated Pull Request
This pull request was generated by our [deployment pipeline]({actionUrl}) as a result of the release of [tgstation-server-v{coreVersion}](https://github.com/tgstation/tgstation-server/releases/tag/tgstation-server-v{coreVersion}). Validation was performed as part of the process.
The user account that created this pull request is available to correct any issues.
Checklist for Pull Requests
- [x] Have you signed the [Contributor License Agreement](https://cla.opensource.microsoft.com/microsoft/winget-pkgs)?
- [x] Is there a linked Issue?
- Shouldn't be possible as this release was just created.
- [x] Have you checked that there aren't other open [pull requests](https://github.com/microsoft/winget-pkgs/pulls) for the same manifest update/change?
- This PR is generated as a direct result of a new release of `tgstation-server` this should be impossible
- [x] Is there a linked Issue? **No**
Manifests
- [x] Have you checked that there aren't other open [pull requests](https://github.com/microsoft/winget-pkgs/pulls) for the same manifest update/change? **Impossible**
- [x] This PR only modifies one (1) manifest
- [x] Have you [validated](https://github.com/microsoft/winget-pkgs/blob/master/doc/Authoring.md#validation) your manifest locally with `winget validate --manifest <path>`?
- Validation is performed as a prerequisite to deployment.
- [x] Have you tested your manifest locally with `winget install --manifest <path>`?
- Manifest installation and uninstallation is performed as a prerequisite to deployment.
- [x] Does your manifest conform to the [1.6 schema](https://github.com/microsoft/winget-pkgs/tree/master/doc/manifest/schema/1.6.0)?
###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/microsoft/winget-pkgs/pull/$PR_NUMBER_SUBST$)";
Note: `<path>` is the directory's name containing the manifest you're submitting.
###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/microsoft/winget-pkgs/pull/$PR_NUMBER_SUBST$)
---
";
if (expectedTemplateSha != null)
{