mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-22 04:27:19 +01:00
Fix issues with JobProgressReporter
This commit is contained in:
@@ -146,7 +146,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
|
||||
public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter progressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
=> DelegateCall(version, installer => installer.CreateInstallation(version, path, installationTask));
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
|
||||
public ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
|
||||
=> DelegateCall(version, installer => installer.DownloadVersion(version, jobProgressReporter, cancellationToken));
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
public abstract ValueTask UpgradeInstallation(EngineVersion version, string path, CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken);
|
||||
public abstract ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken);
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract ValueTask TrustDmbPath(EngineVersion version, string fullDmbPath, CancellationToken cancellationToken);
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask ChangeVersion(
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
EngineVersion version,
|
||||
Stream? customVersionStream,
|
||||
bool allowInstallation,
|
||||
@@ -166,8 +166,11 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
"Acquiring lock on BYOND version {version}...",
|
||||
requiredVersion?.ToString() ?? $"{ActiveVersion} (active)");
|
||||
var versionToUse = requiredVersion ?? ActiveVersion ?? throw new JobException(ErrorCode.EngineNoVersionsInstalled);
|
||||
|
||||
using var progressReporter = new JobProgressReporter();
|
||||
|
||||
var installLock = await AssertAndLockVersion(
|
||||
null,
|
||||
progressReporter,
|
||||
versionToUse,
|
||||
null,
|
||||
requiredVersion != null,
|
||||
@@ -388,7 +391,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <summary>
|
||||
/// Ensures a BYOND <paramref name="version"/> is installed if it isn't already.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="version">The <see cref="EngineVersion"/> to install.</param>
|
||||
/// <param name="customVersionStream">Optional custom zip file <see cref="Stream"/> to use. Will cause a <see cref="Version.Build"/> number to be added.</param>
|
||||
/// <param name="neededForLock">If this BYOND version is required as part of a locking operation.</param>
|
||||
@@ -396,7 +399,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="EngineExecutableLock"/>.</returns>
|
||||
async ValueTask<EngineExecutableLock> AssertAndLockVersion(
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
EngineVersion version,
|
||||
Stream? customVersionStream,
|
||||
bool neededForLock,
|
||||
@@ -443,8 +446,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
{
|
||||
if (installedOrInstalling)
|
||||
{
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Waiting for existing installation job...";
|
||||
progressReporter.StageName = "Waiting for existing installation job...";
|
||||
|
||||
if (neededForLock && !installation.InstallationTask.IsCompleted)
|
||||
logger.LogWarning("The required engine version ({version}) is not readily available! We will have to wait for it to install.", version);
|
||||
@@ -468,8 +470,7 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
else
|
||||
logger.LogInformation("Requested engine version {version} not currently installed. Doing so now...", version);
|
||||
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Running event";
|
||||
progressReporter.StageName = "Running event";
|
||||
|
||||
var versionString = version.ToString();
|
||||
await eventConsumer.HandleEvent(EventType.EngineInstallStart, new List<string> { versionString }, deploymentPipelineProcesses, cancellationToken);
|
||||
@@ -504,14 +505,14 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <summary>
|
||||
/// Installs the files for a given BYOND <paramref name="version"/>.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="version">The <see cref="EngineVersion"/> being installed with the <see cref="Version.Build"/> number set if appropriate.</param>
|
||||
/// <param name="customVersionStream">Custom zip file <see cref="Stream"/> to use. Will cause a <see cref="Version.Build"/> number to be added.</param>
|
||||
/// <param name="deploymentPipelineProcesses">If processes should be launched as part of the deployment pipeline.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
async ValueTask InstallVersionFiles(
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
EngineVersion version,
|
||||
Stream? customVersionStream,
|
||||
bool deploymentPipelineProcesses,
|
||||
@@ -528,14 +529,12 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
try
|
||||
{
|
||||
IEngineInstallationData engineInstallationData;
|
||||
var remainingProgress = 1.0;
|
||||
if (customVersionStream == null)
|
||||
{
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Downloading version";
|
||||
|
||||
engineInstallationData = await engineInstaller.DownloadVersion(version, progressReporter, cancellationToken);
|
||||
|
||||
progressReporter?.ReportProgress(null);
|
||||
using var subReporter = progressReporter.CreateSection("Downloading Version", 0.5);
|
||||
remainingProgress -= 0.5;
|
||||
engineInstallationData = await engineInstaller.DownloadVersion(version, subReporter, cancellationToken);
|
||||
}
|
||||
else
|
||||
#pragma warning disable CA2000 // Dispose objects before losing scope, false positive
|
||||
@@ -544,33 +543,45 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
customVersionStream);
|
||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
||||
|
||||
await using (engineInstallationData)
|
||||
JobProgressReporter remainingReporter;
|
||||
try
|
||||
{
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Cleaning target directory";
|
||||
|
||||
await directoryCleanupTask;
|
||||
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Extracting data";
|
||||
|
||||
logger.LogTrace("Extracting engine to {extractPath}...", installFullPath);
|
||||
await engineInstallationData.ExtractToPath(installFullPath, cancellationToken);
|
||||
remainingReporter = progressReporter.CreateSection(null, remainingProgress);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await engineInstallationData.DisposeAsync();
|
||||
throw;
|
||||
}
|
||||
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Running installation actions";
|
||||
using (remainingReporter)
|
||||
{
|
||||
await using (engineInstallationData)
|
||||
{
|
||||
remainingReporter.StageName = "Cleaning target directory";
|
||||
|
||||
await engineInstaller.Install(version, installFullPath, deploymentPipelineProcesses, cancellationToken);
|
||||
await directoryCleanupTask;
|
||||
remainingReporter.ReportProgress(0.1);
|
||||
remainingReporter.StageName = "Extracting data";
|
||||
|
||||
if (progressReporter != null)
|
||||
progressReporter.StageName = "Writing version file";
|
||||
logger.LogTrace("Extracting engine to {extractPath}...", installFullPath);
|
||||
await engineInstallationData.ExtractToPath(installFullPath, cancellationToken);
|
||||
remainingReporter.ReportProgress(0.3);
|
||||
}
|
||||
|
||||
// make sure to do this last because this is what tells us we have a valid version in the future
|
||||
await ioManager.WriteAllBytes(
|
||||
ioManager.ConcatPath(installFullPath, VersionFileName),
|
||||
Encoding.UTF8.GetBytes(version.ToString()),
|
||||
cancellationToken);
|
||||
remainingReporter.StageName = "Running installation actions";
|
||||
|
||||
await engineInstaller.Install(version, installFullPath, deploymentPipelineProcesses, cancellationToken);
|
||||
|
||||
remainingReporter.ReportProgress(0.9);
|
||||
remainingReporter.StageName = "Writing version file";
|
||||
|
||||
// make sure to do this last because this is what tells us we have a valid version in the future
|
||||
await ioManager.WriteAllBytes(
|
||||
ioManager.ConcatPath(installFullPath, VersionFileName),
|
||||
Encoding.UTF8.GetBytes(version.ToString()),
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
|
||||
@@ -24,10 +24,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// Download a given engine <paramref name="version"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="EngineVersion"/> of the engine to download.</param>
|
||||
/// <param name="jobProgressReporter">The optional <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="jobProgressReporter">The <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IEngineInstallationData"/> for the download.</returns>
|
||||
ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken);
|
||||
ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Does actions necessary to get an extracted installation working.
|
||||
|
||||
@@ -28,14 +28,14 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
/// <summary>
|
||||
/// Change the active <see cref="EngineVersion"/>.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="version">The new <see cref="EngineVersion"/>.</param>
|
||||
/// <param name="customVersionStream">Optional <see cref="Stream"/> of a custom BYOND version zip file.</param>
|
||||
/// <param name="allowInstallation">If an installation should be performed if the <paramref name="version"/> is not installed. If <see langword="false"/> and an installation is required an <see cref="InvalidOperationException"/> will be thrown.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask ChangeVersion(
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
EngineVersion version,
|
||||
Stream? customVersionStream,
|
||||
bool allowInstallation,
|
||||
|
||||
@@ -133,23 +133,32 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter? jobProgressReporter, CancellationToken cancellationToken)
|
||||
public override async ValueTask<IEngineInstallationData> DownloadVersion(EngineVersion version, JobProgressReporter jobProgressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
CheckVersionValidity(version);
|
||||
ArgumentNullException.ThrowIfNull(jobProgressReporter);
|
||||
|
||||
// get a lock on a system wide OD repo
|
||||
Logger.LogTrace("Cloning OD repo...");
|
||||
|
||||
var progressSection1 = jobProgressReporter?.CreateSection("Updating OpenDream git repository", 0.5f);
|
||||
|
||||
var repo = await repositoryManager.CloneRepository(
|
||||
GeneralConfiguration.OpenDreamGitUrl,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
progressSection1,
|
||||
true,
|
||||
cancellationToken);
|
||||
var progressSection1 = jobProgressReporter.CreateSection("Updating OpenDream git repository", 0.5f);
|
||||
IRepository? repo;
|
||||
try
|
||||
{
|
||||
repo = await repositoryManager.CloneRepository(
|
||||
GeneralConfiguration.OpenDreamGitUrl,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
progressSection1,
|
||||
true,
|
||||
cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
progressSection1.Dispose();
|
||||
throw;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -168,19 +177,23 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
var progressSection2 = jobProgressReporter?.CreateSection("Checking out OpenDream version", 0.5f);
|
||||
progressSection1.Dispose();
|
||||
progressSection1 = null;
|
||||
|
||||
var committish = version.SourceSHA
|
||||
?? $"{GeneralConfiguration.OpenDreamGitTagPrefix}{version.Version!.Semver()}";
|
||||
using (var progressSection2 = jobProgressReporter.CreateSection("Checking out OpenDream version", 0.5f))
|
||||
{
|
||||
var committish = version.SourceSHA
|
||||
?? $"{GeneralConfiguration.OpenDreamGitTagPrefix}{version.Version!.Semver()}";
|
||||
|
||||
await repo.CheckoutObject(
|
||||
committish,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
progressSection2,
|
||||
cancellationToken);
|
||||
await repo.CheckoutObject(
|
||||
committish,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
progressSection2,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
if (!await repo.CommittishIsParent("tgs-min-compat", cancellationToken))
|
||||
throw new JobException(ErrorCode.OpenDreamTooOld);
|
||||
@@ -192,6 +205,10 @@ namespace Tgstation.Server.Host.Components.Engine
|
||||
repo?.Dispose();
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
progressSection1?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="password">The optional password used for fetching from submodule repositories.</param>
|
||||
/// <param name="updateSubmodules">If a submodule update should be attempted after the merge.</param>
|
||||
/// <param name="moveCurrentReference">If a hard reset to the target committish should be performed instead of a checkout.</param>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask CheckoutObject(
|
||||
@@ -57,7 +57,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string? password,
|
||||
bool updateSubmodules,
|
||||
bool moveCurrentReference,
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -85,14 +85,14 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <summary>
|
||||
/// Fetch commits from the origin repository.
|
||||
/// </summary>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
|
||||
/// <param name="username">The optional username to fetch from the origin repository.</param>
|
||||
/// <param name="password">The optional password to fetch from the origin repository.</param>
|
||||
/// <param name="deploymentPipeline">If any events created should be marked as part of the deployment pipeline.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask FetchOrigin(
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
string? username,
|
||||
string? password,
|
||||
bool deploymentPipeline,
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="initialBranch">The optional branch to clone.</param>
|
||||
/// <param name="username">The optional username to clone from <paramref name="url"/>.</param>
|
||||
/// <param name="password">The optional password to clone from <paramref name="url"/>.</param>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> for progress of the clone.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for progress of the clone.</param>
|
||||
/// <param name="recurseSubmodules">If submodules should be recusively cloned and initialized.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask{TResult}"/> resulting i the newly cloned <see cref="IRepository"/>, <see langword="null"/> if one already exists.</returns>
|
||||
@@ -44,7 +44,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string? initialBranch,
|
||||
string? username,
|
||||
string? password,
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
bool recurseSubmodules,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
|
||||
@@ -232,13 +232,14 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
logger.LogTrace("Fetching refspec {refSpec}...", refSpec);
|
||||
|
||||
var remote = libGitRepo.Network.Remotes.First();
|
||||
using var fetchReporter = progressReporter.CreateSection($"Fetch {refSpec}", progressFactor);
|
||||
commands.Fetch(
|
||||
libGitRepo,
|
||||
refSpecList,
|
||||
remote,
|
||||
new FetchOptions().Hydrate(
|
||||
logger,
|
||||
progressReporter.CreateSection($"Fetch {refSpec}", progressFactor),
|
||||
fetchReporter,
|
||||
credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
cancellationToken),
|
||||
logMessage);
|
||||
@@ -267,14 +268,14 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
logger.LogTrace("Merging {targetCommitSha} into {currentReference}...", testMergeParameters.TargetCommitSha[..7], Reference);
|
||||
|
||||
using var mergeReporter = progressReporter.CreateSection($"Merge {testMergeParameters.TargetCommitSha[..7]}", progressFactor);
|
||||
result = libGitRepo.Merge(testMergeParameters.TargetCommitSha, sig, new MergeOptions
|
||||
{
|
||||
CommitOnSuccess = commitMessage == null,
|
||||
FailOnConflict = false, // Needed to get conflicting files
|
||||
FastForwardStrategy = FastForwardStrategy.NoFastForward,
|
||||
SkipReuc = true,
|
||||
OnCheckoutProgress = CheckoutProgressHandler(
|
||||
progressReporter.CreateSection($"Merge {testMergeParameters.TargetCommitSha[..7]}", progressFactor)),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(mergeReporter),
|
||||
});
|
||||
}
|
||||
finally
|
||||
@@ -295,7 +296,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var revertTo = originalCommit.CanonicalName ?? originalCommit.Tip.Sha;
|
||||
logger.LogDebug("Merge conflict, aborting and reverting to {revertTarget}", revertTo);
|
||||
progressReporter.ReportProgress(0);
|
||||
RawCheckout(revertTo, false, progressReporter.CreateSection("Hard Reset to {revertTo}", 1.0), cancellationToken);
|
||||
using var revertReporter = progressReporter.CreateSection("Hard Reset to {revertTo}", 1.0);
|
||||
RawCheckout(revertTo, false, revertReporter, cancellationToken);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
@@ -343,8 +345,9 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
if (updateSubmodules)
|
||||
{
|
||||
using var progressReporter2 = progressReporter.CreateSection("Update Submodules", progressFactor);
|
||||
await UpdateSubmodules(
|
||||
progressReporter.CreateSection("Update Submodules", progressFactor),
|
||||
progressReporter2,
|
||||
username,
|
||||
password,
|
||||
false,
|
||||
@@ -377,7 +380,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string? password,
|
||||
bool updateSubmodules,
|
||||
bool moveCurrentReference,
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(committish);
|
||||
@@ -388,10 +391,11 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
() =>
|
||||
{
|
||||
libGitRepo.RemoveUntrackedFiles();
|
||||
using var progressReporter3 = progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0);
|
||||
RawCheckout(
|
||||
committish,
|
||||
moveCurrentReference,
|
||||
progressReporter?.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0),
|
||||
progressReporter3,
|
||||
cancellationToken);
|
||||
},
|
||||
cancellationToken,
|
||||
@@ -399,17 +403,20 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
TaskScheduler.Current);
|
||||
|
||||
if (updateSubmodules)
|
||||
{
|
||||
using var progressReporter2 = progressReporter.CreateSection(null, 1.0 / 3);
|
||||
await UpdateSubmodules(
|
||||
progressReporter?.CreateSection(null, 1.0 / 3),
|
||||
progressReporter2,
|
||||
username,
|
||||
password,
|
||||
false,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async ValueTask FetchOrigin(
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
string? username,
|
||||
string? password,
|
||||
bool deploymentPipeline,
|
||||
@@ -423,13 +430,14 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var remote = libGitRepo.Network.Remotes.First();
|
||||
try
|
||||
{
|
||||
using var subReporter = progressReporter.CreateSection("Fetch Origin", 1.0);
|
||||
var fetchOptions = new FetchOptions
|
||||
{
|
||||
Prune = true,
|
||||
TagFetchMode = TagFetchMode.All,
|
||||
}.Hydrate(
|
||||
logger,
|
||||
progressReporter?.CreateSection("Fetch Origin", 1.0),
|
||||
subReporter,
|
||||
credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
cancellationToken);
|
||||
|
||||
@@ -471,18 +479,23 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
logger.LogTrace("Reset to origin...");
|
||||
var trackedBranch = libGitRepo.Head.TrackedBranch;
|
||||
await eventConsumer.HandleEvent(EventType.RepoResetOrigin, new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, deploymentPipeline, cancellationToken);
|
||||
await ResetToSha(
|
||||
trackedBranch.Tip.Sha,
|
||||
progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0),
|
||||
cancellationToken);
|
||||
|
||||
using (var progressReporter2 = progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0))
|
||||
await ResetToSha(
|
||||
trackedBranch.Tip.Sha,
|
||||
progressReporter2,
|
||||
cancellationToken);
|
||||
|
||||
if (updateSubmodules)
|
||||
{
|
||||
using var progressReporter3 = progressReporter.CreateSection(null, 1.0 / 3);
|
||||
await UpdateSubmodules(
|
||||
progressReporter.CreateSection(null, 1.0 / 3),
|
||||
progressReporter3,
|
||||
username,
|
||||
password,
|
||||
deploymentPipeline,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -684,9 +697,10 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
await Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
using var resetProgress = progressReporter.CreateSection("Hard reset and remove untracked files", 0.1);
|
||||
libGitRepo.Reset(ResetMode.Hard, libGitRepo.Head.Tip, new CheckoutOptions
|
||||
{
|
||||
OnCheckoutProgress = CheckoutProgressHandler(progressReporter.CreateSection("Hard reset and remove untracked files", 0.1)),
|
||||
OnCheckoutProgress = CheckoutProgressHandler(resetProgress),
|
||||
});
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
libGitRepo.RemoveUntrackedFiles();
|
||||
@@ -699,10 +713,11 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var remainingProgressFactor = 0.9;
|
||||
if (!synchronizeTrackedBranch)
|
||||
{
|
||||
using var progressReporter2 = progressReporter.CreateSection("Push to temporary branch", remainingProgressFactor);
|
||||
await PushHeadToTemporaryBranch(
|
||||
username,
|
||||
password,
|
||||
progressReporter.CreateSection("Push to temporary branch", remainingProgressFactor),
|
||||
progressReporter2,
|
||||
cancellationToken);
|
||||
return false;
|
||||
}
|
||||
@@ -722,13 +737,24 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var remote = libGitRepo.Network.Remotes.First();
|
||||
try
|
||||
{
|
||||
libGitRepo.Network.Push(
|
||||
libGitRepo.Head,
|
||||
GeneratePushOptions(
|
||||
progressReporter.CreateSection("Push to origin", remainingProgressFactor),
|
||||
username,
|
||||
password,
|
||||
cancellationToken));
|
||||
using var pushReporter = progressReporter.CreateSection("Push to origin", remainingProgressFactor);
|
||||
var (pushOptions, progressReporters) = GeneratePushOptions(
|
||||
pushReporter,
|
||||
username,
|
||||
password,
|
||||
cancellationToken);
|
||||
try
|
||||
{
|
||||
libGitRepo.Network.Push(
|
||||
libGitRepo.Head,
|
||||
pushOptions);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var progressReporter in progressReporters)
|
||||
progressReporter.Dispose();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (NonFastForwardException)
|
||||
@@ -882,9 +908,9 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// </summary>
|
||||
/// <param name="committish">The committish to checkout.</param>
|
||||
/// <param name="moveCurrentReference">If a hard reset should actually be performed.</param>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> for the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
void RawCheckout(string committish, bool moveCurrentReference, JobProgressReporter? progressReporter, CancellationToken cancellationToken)
|
||||
void RawCheckout(string committish, bool moveCurrentReference, JobProgressReporter progressReporter, CancellationToken cancellationToken)
|
||||
{
|
||||
logger.LogTrace("Checkout: {committish}", committish);
|
||||
|
||||
@@ -893,13 +919,10 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
CheckoutModifiers = CheckoutModifiers.Force,
|
||||
};
|
||||
|
||||
if (progressReporter != null)
|
||||
{
|
||||
var stage = $"Checkout {committish}";
|
||||
progressReporter = progressReporter.CreateSection(stage, 1.0);
|
||||
progressReporter.ReportProgress(0);
|
||||
checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(progressReporter);
|
||||
}
|
||||
var stage = $"Checkout {committish}";
|
||||
using var newProgressReporter = progressReporter.CreateSection(stage, 1.0);
|
||||
newProgressReporter.ReportProgress(0);
|
||||
checkoutOptions.OnCheckoutProgress = CheckoutProgressHandler(newProgressReporter);
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -976,9 +999,38 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
try
|
||||
{
|
||||
var forcePushString = String.Format(CultureInfo.InvariantCulture, "+{0}:{0}", branch.CanonicalName);
|
||||
libGitRepo.Network.Push(remote, forcePushString, GeneratePushOptions(progressReporter.CreateSection(null, 0.9), username, password, cancellationToken));
|
||||
|
||||
using (var mainPushReporter = progressReporter.CreateSection(null, 0.9))
|
||||
{
|
||||
var (pushOptions, progressReporters) = GeneratePushOptions(
|
||||
mainPushReporter,
|
||||
username,
|
||||
password,
|
||||
cancellationToken);
|
||||
|
||||
try
|
||||
{
|
||||
libGitRepo.Network.Push(remote, forcePushString, pushOptions);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var progressReporter in progressReporters)
|
||||
progressReporter.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
var removalString = String.Format(CultureInfo.InvariantCulture, ":{0}", branch.CanonicalName);
|
||||
libGitRepo.Network.Push(remote, removalString, GeneratePushOptions(progressReporter.CreateSection(null, 0.1), username, password, cancellationToken));
|
||||
using var forcePushReporter = progressReporter.CreateSection(null, 0.1);
|
||||
var (forcePushOptions, forcePushReporters) = GeneratePushOptions(forcePushReporter, username, password, cancellationToken);
|
||||
try
|
||||
{
|
||||
libGitRepo.Network.Push(remote, removalString, forcePushOptions);
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var subForcePushReporter in forcePushReporters)
|
||||
forcePushReporter.Dispose();
|
||||
}
|
||||
}
|
||||
catch (UserCancelledException)
|
||||
{
|
||||
@@ -1005,32 +1057,39 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="username">The username for the <see cref="credentialsProvider"/>.</param>
|
||||
/// <param name="password">The password for the <see cref="credentialsProvider"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A new set of <see cref="PushOptions"/>.</returns>
|
||||
PushOptions GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
|
||||
/// <returns>A new set of <see cref="PushOptions"/> and the associated <see cref="JobProgressReporter"/>s based off <paramref name="progressReporter"/>.</returns>
|
||||
(PushOptions PushOptions, IEnumerable<JobProgressReporter> SubProgressReporters) GeneratePushOptions(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
|
||||
{
|
||||
var subProgressReporter = progressReporter.CreateSection(null, 0.5);
|
||||
var packFileCountingReporter = progressReporter.CreateSection(null, 0.25);
|
||||
var packFileDeltafyingReporter = progressReporter.CreateSection(null, 0.25);
|
||||
var transferProgressReporter = progressReporter.CreateSection(null, 0.5);
|
||||
|
||||
return new PushOptions
|
||||
{
|
||||
OnPackBuilderProgress = (stage, current, total) =>
|
||||
return (
|
||||
PushOptions: new PushOptions
|
||||
{
|
||||
var baseProgress = stage == PackBuilderStage.Counting ? 0 : 0.5;
|
||||
var addon = total > 0 && current <= total ? (0.5 * ((double)current / total)) : 0;
|
||||
progressReporter.ReportProgress(baseProgress + addon);
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
OnPackBuilderProgress = (stage, current, total) =>
|
||||
{
|
||||
if (total < current)
|
||||
total = current;
|
||||
|
||||
var percentage = ((double)current) / total;
|
||||
(stage == PackBuilderStage.Counting ? packFileCountingReporter : packFileDeltafyingReporter).ReportProgress(percentage);
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
},
|
||||
OnNegotiationCompletedBeforePush = (a) => !cancellationToken.IsCancellationRequested,
|
||||
OnPushTransferProgress = (a, sentBytes, totalBytes) =>
|
||||
{
|
||||
packFileCountingReporter.ReportProgress((double)sentBytes / totalBytes);
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
},
|
||||
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
},
|
||||
OnNegotiationCompletedBeforePush = (a) =>
|
||||
SubProgressReporters: new List<JobProgressReporter>
|
||||
{
|
||||
subProgressReporter = progressReporter.CreateSection(null, 0.5);
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
},
|
||||
OnPushTransferProgress = (a, sentBytes, totalBytes) =>
|
||||
{
|
||||
progressReporter.ReportProgress((double)sentBytes / totalBytes);
|
||||
return !cancellationToken.IsCancellationRequested;
|
||||
},
|
||||
CredentialsProvider = credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
};
|
||||
packFileCountingReporter,
|
||||
packFileDeltafyingReporter,
|
||||
transferProgressReporter,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1054,7 +1113,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
|
||||
ValueTask UpdateSubmodules(
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
string? username,
|
||||
string? password,
|
||||
bool deploymentPipeline,
|
||||
@@ -1062,7 +1121,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
logger.LogTrace("Updating submodules {withOrWithout} credentials...", username == null ? "without" : "with");
|
||||
|
||||
async ValueTask RecursiveUpdateSubmodules(LibGit2Sharp.IRepository parentRepository, JobProgressReporter? currentProgressReporter, string parentGitDirectory)
|
||||
async ValueTask RecursiveUpdateSubmodules(LibGit2Sharp.IRepository parentRepository, JobProgressReporter currentProgressReporter, string parentGitDirectory)
|
||||
{
|
||||
var submoduleCount = libGitRepo.Submodules.Count();
|
||||
if (submoduleCount == 0)
|
||||
@@ -1081,15 +1140,16 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
OnCheckoutNotify = (_, _) => !cancellationToken.IsCancellationRequested,
|
||||
};
|
||||
|
||||
using var fetchReporter = currentProgressReporter.CreateSection($"Fetch submodule {submodule.Name}", factor);
|
||||
|
||||
submoduleUpdateOptions.FetchOptions.Hydrate(
|
||||
logger,
|
||||
currentProgressReporter?.CreateSection($"Fetch submodule {submodule.Name}", factor),
|
||||
fetchReporter,
|
||||
credentialsProvider.GenerateCredentialsHandler(username, password),
|
||||
cancellationToken);
|
||||
|
||||
if (currentProgressReporter != null)
|
||||
submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler(
|
||||
currentProgressReporter.CreateSection($"Checkout submodule {submodule.Name}", factor));
|
||||
using var checkoutReporter = currentProgressReporter.CreateSection($"Checkout submodule {submodule.Name}", factor);
|
||||
submoduleUpdateOptions.OnCheckoutProgress = CheckoutProgressHandler(checkoutReporter);
|
||||
|
||||
logger.LogDebug("Updating submodule {submoduleName}...", submodule.Name);
|
||||
Task RawSubModuleUpdate() => Task.Factory.StartNew(
|
||||
@@ -1106,7 +1166,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
// workaround for https://github.com/libgit2/libgit2/issues/3820
|
||||
// kill off the modules/ folder in .git and try again
|
||||
currentProgressReporter?.ReportProgress(null);
|
||||
currentProgressReporter.ReportProgress(0);
|
||||
credentialsProvider.CheckBadCredentialsException(ex);
|
||||
logger.LogWarning(ex, "Initial update of submodule {submoduleName} failed. Deleting submodule directories and re-attempting...", submodule.Name);
|
||||
|
||||
@@ -1145,9 +1205,11 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
using var submoduleRepo = await submoduleFactory.CreateFromPath(
|
||||
submodulePath,
|
||||
cancellationToken);
|
||||
|
||||
using var submoduleReporter = currentProgressReporter.CreateSection($"Entering submodule \"{submodule.Name}\"...", factor);
|
||||
await RecursiveUpdateSubmodules(
|
||||
submoduleRepo,
|
||||
currentProgressReporter?.CreateSection($"Entering submodule \"{submodule.Name}\"...", factor),
|
||||
submoduleReporter,
|
||||
submodulePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string? initialBranch,
|
||||
string? username,
|
||||
string? password,
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
bool recurseSubmodules,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -146,8 +146,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
if (!await ioManager.DirectoryExists(repositoryPath, cancellationToken))
|
||||
try
|
||||
{
|
||||
var cloneProgressReporter = progressReporter?.CreateSection(null, 0.75f);
|
||||
var checkoutProgressReporter = progressReporter?.CreateSection(null, 0.25f);
|
||||
using var cloneProgressReporter = progressReporter.CreateSection(null, 0.75f);
|
||||
using var checkoutProgressReporter = progressReporter.CreateSection(null, 0.25f);
|
||||
var cloneOptions = new CloneOptions
|
||||
{
|
||||
RecurseSubmodules = recurseSubmodules,
|
||||
|
||||
@@ -173,10 +173,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var numSteps = (model.NewTestMerges?.Count ?? 0) + (model.UpdateFromOrigin == true ? 1 : 0) + (!modelHasShaOrReference ? 2 : (hardResettingToOriginReference ? 3 : 1));
|
||||
var progressFactor = 1.0 / numSteps;
|
||||
|
||||
JobProgressReporter NextProgressReporter(string? stage)
|
||||
{
|
||||
return progressReporter.CreateSection(stage, progressFactor);
|
||||
}
|
||||
JobProgressReporter NextProgressReporter(string? stage) => progressReporter.CreateSection(stage, progressFactor);
|
||||
|
||||
progressReporter.ReportProgress(0);
|
||||
|
||||
@@ -246,29 +243,35 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
{
|
||||
if (!repo.Tracking)
|
||||
throw new JobException(ErrorCode.RepoReferenceRequired);
|
||||
await repo.FetchOrigin(
|
||||
NextProgressReporter("Fetch Origin"),
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
false,
|
||||
cancellationToken);
|
||||
using (var fetchReporter = NextProgressReporter("Fetch Origin"))
|
||||
await repo.FetchOrigin(
|
||||
fetchReporter,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
false,
|
||||
cancellationToken);
|
||||
|
||||
if (!modelHasShaOrReference)
|
||||
{
|
||||
var fastForward = await repo.MergeOrigin(
|
||||
NextProgressReporter("Merge Origin"),
|
||||
committerName,
|
||||
currentModel.CommitterEmail!,
|
||||
false,
|
||||
cancellationToken);
|
||||
bool? fastForward;
|
||||
using (var mergeReporter = NextProgressReporter("Merge Origin"))
|
||||
fastForward = await repo.MergeOrigin(
|
||||
mergeReporter,
|
||||
committerName,
|
||||
currentModel.CommitterEmail!,
|
||||
false,
|
||||
cancellationToken);
|
||||
|
||||
if (!fastForward.HasValue)
|
||||
throw new JobException(ErrorCode.RepoMergeConflict);
|
||||
|
||||
lastRevisionInfo!.OriginCommitSha = await repo.GetOriginSha(cancellationToken);
|
||||
await UpdateRevInfo();
|
||||
if (fastForward.Value)
|
||||
{
|
||||
using var syncReporter = NextProgressReporter("Sychronize");
|
||||
await repo.Synchronize(
|
||||
NextProgressReporter("Sychronize"),
|
||||
syncReporter,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName!,
|
||||
@@ -279,7 +282,7 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
postUpdateSha = repo.Head;
|
||||
}
|
||||
else
|
||||
NextProgressReporter(null).ReportProgress(1.0);
|
||||
NextProgressReporter(null).Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,39 +306,44 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
if ((isSha && model.Reference != null) || (!isSha && model.CheckoutSha != null))
|
||||
throw new JobException(ErrorCode.RepoSwappedShaOrReference);
|
||||
|
||||
await repo.CheckoutObject(
|
||||
committish,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
false,
|
||||
NextProgressReporter("Checkout"),
|
||||
cancellationToken);
|
||||
using (var checkoutReporter = NextProgressReporter("Checkout"))
|
||||
await repo.CheckoutObject(
|
||||
committish,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
false,
|
||||
checkoutReporter,
|
||||
cancellationToken);
|
||||
await CallLoadRevInfo(); // we've either seen origin before or what we're checking out is on origin
|
||||
}
|
||||
else
|
||||
NextProgressReporter(null).ReportProgress(1.0);
|
||||
NextProgressReporter(null).Dispose();
|
||||
|
||||
if (hardResettingToOriginReference)
|
||||
{
|
||||
if (!repo.Tracking)
|
||||
throw new JobException(ErrorCode.RepoReferenceNotTracking);
|
||||
await repo.ResetToOrigin(
|
||||
NextProgressReporter("Reset to Origin"),
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
false,
|
||||
cancellationToken);
|
||||
await repo.Synchronize(
|
||||
NextProgressReporter("Synchronize"),
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName!,
|
||||
currentModel.CommitterEmail!,
|
||||
true,
|
||||
false,
|
||||
cancellationToken);
|
||||
using (var resetReporter = NextProgressReporter("Reset to Origin"))
|
||||
await repo.ResetToOrigin(
|
||||
resetReporter,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
false,
|
||||
cancellationToken);
|
||||
|
||||
using (var syncReporter = NextProgressReporter("Synchronize"))
|
||||
await repo.Synchronize(
|
||||
syncReporter,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName!,
|
||||
currentModel.CommitterEmail!,
|
||||
true,
|
||||
false,
|
||||
cancellationToken);
|
||||
|
||||
await CallLoadRevInfo();
|
||||
|
||||
// repo head is on origin so force this
|
||||
@@ -486,7 +494,8 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
// goteem
|
||||
var commitSha = revInfoWereLookingFor.CommitSha!;
|
||||
logger.LogDebug("Reusing existing SHA {sha}...", commitSha);
|
||||
await repo.ResetToSha(commitSha, NextProgressReporter($"Reset to {commitSha[..7]}"), cancellationToken);
|
||||
using var resetReporter = NextProgressReporter($"Reset to {commitSha[..7]}");
|
||||
await repo.ResetToSha(commitSha, resetReporter, cancellationToken);
|
||||
lastRevisionInfo = revInfoWereLookingFor;
|
||||
}
|
||||
|
||||
@@ -499,15 +508,17 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
|
||||
var fullTestMergeTask = repo.GetTestMerge(newTestMerge, currentModel, cancellationToken);
|
||||
|
||||
var mergeResult = await repo.AddTestMerge(
|
||||
newTestMerge,
|
||||
committerName,
|
||||
currentModel.CommitterEmail!,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
NextProgressReporter($"Test merge #{newTestMerge.Number}"),
|
||||
cancellationToken);
|
||||
TestMergeResult mergeResult;
|
||||
using (var testMergeReporter = NextProgressReporter($"Test merge #{newTestMerge.Number}"))
|
||||
mergeResult = await repo.AddTestMerge(
|
||||
newTestMerge,
|
||||
committerName,
|
||||
currentModel.CommitterEmail!,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
updateSubmodules,
|
||||
testMergeReporter,
|
||||
cancellationToken);
|
||||
|
||||
if (mergeResult.Status == MergeStatus.Conflicts)
|
||||
throw new JobException(
|
||||
@@ -546,15 +557,17 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var currentHead = repo.Head;
|
||||
if (currentModel.PushTestMergeCommits!.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead)))
|
||||
{
|
||||
await repo.Synchronize(
|
||||
NextProgressReporter("Synchronize"),
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName!,
|
||||
currentModel.CommitterEmail!,
|
||||
false,
|
||||
false,
|
||||
cancellationToken);
|
||||
using (var syncReporter = NextProgressReporter("Synchronize"))
|
||||
await repo.Synchronize(
|
||||
syncReporter,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
currentModel.CommitterName!,
|
||||
currentModel.CommitterEmail!,
|
||||
false,
|
||||
false,
|
||||
cancellationToken);
|
||||
|
||||
await UpdateRevInfo();
|
||||
}
|
||||
}
|
||||
@@ -568,17 +581,19 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
var secondStep = startReference != null && repo.Head != startSha;
|
||||
|
||||
// DCTx2: Cancellation token is for job, operations should always run
|
||||
await repo.CheckoutObject(
|
||||
startReference ?? startSha,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
true,
|
||||
false,
|
||||
progressReporter.CreateSection($"Checkout {startReference ?? startSha[..7]}", secondStep ? 0.5 : 1.0),
|
||||
default);
|
||||
using (var checkoutReporter = progressReporter.CreateSection($"Checkout {startReference ?? startSha[..7]}", secondStep ? 0.5 : 1.0))
|
||||
await repo.CheckoutObject(
|
||||
startReference ?? startSha,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
true,
|
||||
false,
|
||||
checkoutReporter,
|
||||
default);
|
||||
|
||||
if (secondStep)
|
||||
await repo.ResetToSha(startSha, progressReporter.CreateSection($"Hard reset to SHA {startSha[..7]}", 0.5), default);
|
||||
using (var resetReporter = progressReporter.CreateSection($"Hard reset to SHA {startSha[..7]}", 0.5))
|
||||
await repo.ResetToSha(startSha, resetReporter, default);
|
||||
|
||||
throw;
|
||||
}
|
||||
@@ -608,32 +623,35 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
string? oldReference;
|
||||
string oldSha;
|
||||
ValueTask deleteTask;
|
||||
using (var oldRepo = await instance.RepositoryManager.LoadRepository(cancellationToken))
|
||||
using (var deleteReporter = progressReporter.CreateSection("Deleting Old Repository", 0.1))
|
||||
{
|
||||
if (oldRepo == null)
|
||||
throw new JobException(ErrorCode.RepoMissing);
|
||||
using (var oldRepo = await instance.RepositoryManager.LoadRepository(cancellationToken))
|
||||
{
|
||||
if (oldRepo == null)
|
||||
throw new JobException(ErrorCode.RepoMissing);
|
||||
|
||||
origin = oldRepo.Origin;
|
||||
oldSha = oldRepo.Head;
|
||||
oldReference = oldRepo.Reference;
|
||||
if (oldReference == Repository.NoReference)
|
||||
oldReference = null;
|
||||
origin = oldRepo.Origin;
|
||||
oldSha = oldRepo.Head;
|
||||
oldReference = oldRepo.Reference;
|
||||
if (oldReference == Repository.NoReference)
|
||||
oldReference = null;
|
||||
|
||||
progressReporter.StageName = "Deleting Old Repository";
|
||||
deleteTask = instance.RepositoryManager.DeleteRepository(cancellationToken);
|
||||
deleteTask = instance.RepositoryManager.DeleteRepository(cancellationToken);
|
||||
}
|
||||
|
||||
await deleteTask;
|
||||
}
|
||||
|
||||
await deleteTask;
|
||||
progressReporter.ReportProgress(0.1);
|
||||
IRepository newRepo;
|
||||
try
|
||||
{
|
||||
using var cloneReporter = progressReporter.CreateSection("Cloning New Repository", 0.8);
|
||||
newRepo = await instance.RepositoryManager.CloneRepository(
|
||||
origin,
|
||||
oldReference,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
progressReporter.CreateSection("Cloning New Repository", 0.8),
|
||||
cloneReporter,
|
||||
true, // TODO: Make configurable maybe...
|
||||
cancellationToken)
|
||||
?? throw new JobException("A race condition occurred while recloning the repository. Somehow, it was fully cloned instantly after being deleted!"); // I'll take lines of code that should never be hit for $10k
|
||||
@@ -655,14 +673,17 @@ namespace Tgstation.Server.Host.Components.Repository
|
||||
}
|
||||
|
||||
using (newRepo)
|
||||
using (var checkoutReporter = progressReporter.CreateSection("Checking out previous Detached Commit", 0.1))
|
||||
{
|
||||
await newRepo.CheckoutObject(
|
||||
oldSha,
|
||||
currentModel.AccessUser,
|
||||
currentModel.AccessToken,
|
||||
false,
|
||||
oldReference != null,
|
||||
progressReporter.CreateSection("Checking out previous Detached Commit", 0.1),
|
||||
checkoutReporter,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,8 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|
||||
try
|
||||
{
|
||||
await byondManager.ChangeVersion(null, model.EngineVersion, null, false, cancellationToken);
|
||||
using var progressReporter = new JobProgressReporter();
|
||||
await byondManager.ChangeVersion(progressReporter, model.EngineVersion, null, false, cancellationToken);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
|
||||
@@ -20,14 +20,14 @@ namespace Tgstation.Server.Host.Extensions
|
||||
/// </summary>
|
||||
/// <param name="fetchOptions">The <see cref="FetchOptions"/> to hydrate.</param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the operation.</param>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/>.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/>.</param>
|
||||
/// <param name="credentialsHandler">The optional <see cref="CredentialsHandler"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>The hydrated <paramref name="fetchOptions"/>.</returns>
|
||||
public static FetchOptions Hydrate(
|
||||
this FetchOptions fetchOptions,
|
||||
ILogger logger,
|
||||
JobProgressReporter? progressReporter,
|
||||
JobProgressReporter progressReporter,
|
||||
CredentialsHandler credentialsHandler,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -60,10 +60,10 @@ namespace Tgstation.Server.Host.Extensions
|
||||
/// Generate a <see cref="LibGit2Sharp.Handlers.TransferProgressHandler"/> from a given <paramref name="progressReporter"/> and <paramref name="cancellationToken"/>.
|
||||
/// </summary>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the operation.</param>
|
||||
/// <param name="progressReporter">The optional <see cref="JobProgressReporter"/> of the operation.</param>
|
||||
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> of the operation.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
|
||||
/// <returns>A new <see cref="LibGit2Sharp.Handlers.TransferProgressHandler"/> based on <paramref name="progressReporter"/>.</returns>
|
||||
static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter? progressReporter, CancellationToken cancellationToken) => transferProgress =>
|
||||
static TransferProgressHandler TransferProgressHandler(ILogger logger, JobProgressReporter progressReporter, CancellationToken cancellationToken) => transferProgress =>
|
||||
{
|
||||
double? percentage;
|
||||
var totalObjectsToProcess = transferProgress.TotalObjects * 2;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
using Tgstation.Server.Host.Models;
|
||||
|
||||
@@ -9,7 +10,7 @@ namespace Tgstation.Server.Host.Jobs
|
||||
/// <summary>
|
||||
/// Progress reporter for a <see cref="Job"/>.
|
||||
/// </summary>
|
||||
public sealed class JobProgressReporter
|
||||
public sealed class JobProgressReporter : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the current stage.
|
||||
@@ -52,6 +53,24 @@ namespace Tgstation.Server.Host.Jobs
|
||||
/// </summary>
|
||||
double sectionProgression;
|
||||
|
||||
/// <summary>
|
||||
/// The total progress reserved for use in this section.
|
||||
/// </summary>
|
||||
double? sectionReservations;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JobProgressReporter"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>This variant has no function.</remarks>
|
||||
public JobProgressReporter()
|
||||
: this(
|
||||
NullLogger<JobProgressReporter>.Instance,
|
||||
null,
|
||||
(_, _) => { },
|
||||
false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JobProgressReporter"/> class.
|
||||
/// </summary>
|
||||
@@ -59,27 +78,84 @@ namespace Tgstation.Server.Host.Jobs
|
||||
/// <param name="stageName">The value of <see cref="StageName"/>.</param>
|
||||
/// <param name="callback">The value of <see cref="callback"/>.</param>
|
||||
public JobProgressReporter(ILogger<JobProgressReporter> logger, string? stageName, Action<string?, double?> callback)
|
||||
: this(
|
||||
logger,
|
||||
stageName,
|
||||
callback,
|
||||
true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JobProgressReporter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The value of <see cref="logger"/>.</param>
|
||||
/// <param name="stageName">The value of <see cref="StageName"/>.</param>
|
||||
/// <param name="callback">The value of <see cref="callback"/>.</param>
|
||||
/// <param name="setStageName">If <see langword="true"/> an initial call to <paramref name="callback"/> will be made with only the <paramref name="stageName"/>.</param>
|
||||
private JobProgressReporter(ILogger<JobProgressReporter> logger, string? stageName, Action<string?, double?> callback, bool setStageName)
|
||||
{
|
||||
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
this.callback = callback ?? throw new ArgumentNullException(nameof(callback));
|
||||
StageName = stageName;
|
||||
if (setStageName)
|
||||
{
|
||||
StageName = stageName;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.stageName = stageName;
|
||||
}
|
||||
|
||||
logger.LogDebug("Job progress reporter created. Stage: {stageName}", stageName ?? "(null)");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (sectionReservations.HasValue)
|
||||
if (sectionReservations.Value != 1.0)
|
||||
{
|
||||
// not an error, processes can throw
|
||||
sectionReservations = null;
|
||||
}
|
||||
else if (sectionProgression < 1.0)
|
||||
{
|
||||
logger.LogError(
|
||||
new InvalidOperationException($"Parent progress reporter has child sections that didn't complete! Current: {sectionProgression}"),
|
||||
"TGS BUG: Progress reporter children didn't complete!");
|
||||
sectionReservations = null;
|
||||
}
|
||||
|
||||
if (!sectionReservations.HasValue)
|
||||
ReportProgress(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Report progress.
|
||||
/// </summary>
|
||||
/// <param name="progress">A percentage value from 0.0f-1.0f.</param>
|
||||
public void ReportProgress(double? progress)
|
||||
{
|
||||
if (sectionReservations.HasValue)
|
||||
if (progress == 0)
|
||||
{
|
||||
// might be a stage reset
|
||||
sectionReservations = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError(
|
||||
new InvalidOperationException("Progress reporter is reporting progress with existing nested sections!"),
|
||||
"TGS BUG: A progress reporter is using mixed local and nested progress, this is not supported");
|
||||
}
|
||||
|
||||
var clampedProgress = progress;
|
||||
if (progress.HasValue)
|
||||
if (progress > 1 || progress < 0)
|
||||
{
|
||||
logger.LogError(
|
||||
new ArgumentOutOfRangeException(nameof(progress), progress, "Progress must be a value from 0-1!"),
|
||||
"Invalid progress value for stage {stageName}",
|
||||
"TGS BUG: Invalid progress value for stage {stageName}",
|
||||
StageName ?? "(null)");
|
||||
clampedProgress = null;
|
||||
}
|
||||
@@ -103,16 +179,27 @@ namespace Tgstation.Server.Host.Jobs
|
||||
{
|
||||
logger.LogError(
|
||||
new ArgumentOutOfRangeException(nameof(percentage), percentage, "Percentage must be a value from 0-1!"),
|
||||
"Invalid percentage value for stage {newStageName}! Clamping...",
|
||||
"TGS BUG: Invalid percentage value for stage {newStageName}! Clamping...",
|
||||
newStageName ?? "(null)");
|
||||
|
||||
percentage = Math.Min(Math.Max(percentage, 0.0), 1.0);
|
||||
}
|
||||
|
||||
var childBaseProgress = sectionProgression;
|
||||
if (percentage + childBaseProgress > 1.0)
|
||||
if (!sectionReservations.HasValue)
|
||||
{
|
||||
var remainingPercentage = 1.0 - childBaseProgress;
|
||||
if (sectionProgression != 0)
|
||||
{
|
||||
logger.LogError(
|
||||
new InvalidOperationException("Progress reporter is creating a section with local progress!"),
|
||||
"TGS BUG: A progress reporter is using mixed local and nested progress, this is not supported");
|
||||
}
|
||||
|
||||
sectionReservations = 0;
|
||||
}
|
||||
|
||||
if (percentage + sectionReservations.Value > 1.0001) // floating point >.<
|
||||
{
|
||||
var remainingPercentage = 1.0 - sectionReservations.Value;
|
||||
logger.LogError(
|
||||
"Stage {newStageName} is overbudgeted ({budget}/{remainingPercentage})! Clamping...",
|
||||
newStageName,
|
||||
@@ -121,6 +208,9 @@ namespace Tgstation.Server.Host.Jobs
|
||||
percentage = remainingPercentage;
|
||||
}
|
||||
|
||||
Math.Min(sectionReservations.Value + percentage, 1);
|
||||
|
||||
var childLocalProgress = 0.0;
|
||||
var newReporter = new JobProgressReporter(
|
||||
logger,
|
||||
newStageName,
|
||||
@@ -133,11 +223,17 @@ namespace Tgstation.Server.Host.Jobs
|
||||
return;
|
||||
}
|
||||
|
||||
var childLocalProgress = progress.Value * percentage;
|
||||
var progressWithoutChild = sectionProgression - childLocalProgress;
|
||||
childLocalProgress = progress.Value * percentage;
|
||||
|
||||
// floating point >.<
|
||||
sectionProgression = Math.Min(progressWithoutChild + childLocalProgress, 1);
|
||||
if (sectionProgression > 9.9999)
|
||||
sectionProgression = 1;
|
||||
|
||||
sectionProgression = childLocalProgress + childBaseProgress;
|
||||
callback(currentStage, sectionProgression);
|
||||
});
|
||||
},
|
||||
false);
|
||||
|
||||
newReporter.ReportProgress(0);
|
||||
return newReporter;
|
||||
|
||||
@@ -460,14 +460,16 @@ namespace Tgstation.Server.Host.Jobs
|
||||
QueueHubUpdate(job.ToApi(), false);
|
||||
|
||||
logger.LogTrace("Starting job...");
|
||||
using var progressReporter = new JobProgressReporter(
|
||||
loggerFactory.CreateLogger<JobProgressReporter>(),
|
||||
null,
|
||||
UpdateProgress);
|
||||
using var innerReporter = progressReporter.CreateSection(null, 1.0);
|
||||
await operation(
|
||||
instanceCoreProvider.GetInstance(job.Instance!),
|
||||
databaseContextFactory,
|
||||
job,
|
||||
new JobProgressReporter(
|
||||
loggerFactory.CreateLogger<JobProgressReporter>(),
|
||||
null,
|
||||
UpdateProgress),
|
||||
innerReporter,
|
||||
cancellationToken);
|
||||
|
||||
logger.LogDebug("Job {jobId} completed!", job.Id);
|
||||
|
||||
@@ -13,6 +13,7 @@ using Tgstation.Server.Common.Http;
|
||||
using Tgstation.Server.Host.Components.Repository;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
using Tgstation.Server.Host.System;
|
||||
using Tgstation.Server.Host.Utils;
|
||||
|
||||
@@ -52,7 +53,7 @@ namespace Tgstation.Server.Host.Components.Engine.Tests
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
It.IsNotNull<JobProgressReporter>(),
|
||||
true,
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Callback(() => ++cloneAttempts)
|
||||
@@ -85,7 +86,7 @@ namespace Tgstation.Server.Host.Components.Engine.Tests
|
||||
Engine = EngineType.OpenDream,
|
||||
SourceSHA = new string('a', Limits.MaximumCommitShaLength),
|
||||
},
|
||||
null,
|
||||
new JobProgressReporter(),
|
||||
CancellationToken.None);
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ using Remora.Rest.Core;
|
||||
using Tgstation.Server.Host.Components.Events;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
|
||||
namespace Tgstation.Server.Host.Components.Repository.Tests
|
||||
{
|
||||
@@ -86,7 +87,7 @@ namespace Tgstation.Server.Host.Components.Repository.Tests
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new JobProgressReporter(),
|
||||
false,
|
||||
CancellationToken.None);
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using Moq;
|
||||
|
||||
namespace Tgstation.Server.Host.Jobs.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class TestJobProgressReporter
|
||||
{
|
||||
string expectedStageName = null;
|
||||
double? expectedProgress = null;
|
||||
void Validate(string stageName, double? progress)
|
||||
{
|
||||
Assert.AreEqual(expectedStageName, stageName);
|
||||
Assert.AreEqual(expectedProgress, progress);
|
||||
}
|
||||
|
||||
JobProgressReporter Setup()
|
||||
{
|
||||
expectedStageName = null;
|
||||
expectedProgress = 0;
|
||||
return new JobProgressReporter(
|
||||
Mock.Of<ILogger<JobProgressReporter>>(),
|
||||
null,
|
||||
Validate);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestBasicUsage()
|
||||
{
|
||||
var progressReporter = Setup();
|
||||
|
||||
expectedProgress = 0.4;
|
||||
progressReporter.ReportProgress(0.4);
|
||||
expectedProgress = 1.0;
|
||||
progressReporter.ReportProgress(1.0);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestNestedUsage()
|
||||
{
|
||||
var progressReporter = Setup();
|
||||
|
||||
expectedStageName = "Test1";
|
||||
var subReporter1 = progressReporter.CreateSection("Test1", 0.5);
|
||||
expectedProgress = 0.1;
|
||||
subReporter1.ReportProgress(0.2);
|
||||
expectedProgress = 0.4;
|
||||
subReporter1.ReportProgress(0.8);
|
||||
|
||||
expectedStageName = "Test2";
|
||||
var subReporter2 = progressReporter.CreateSection("Test2", 0.5);
|
||||
|
||||
expectedStageName = "Test1";
|
||||
expectedProgress = 0.5;
|
||||
subReporter1.ReportProgress(1);
|
||||
|
||||
expectedStageName = "Test2";
|
||||
expectedProgress = 0.6;
|
||||
subReporter2.ReportProgress(0.2);
|
||||
expectedProgress = 1.0;
|
||||
subReporter2.ReportProgress(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ using Tgstation.Server.Host.Components.Events;
|
||||
using Tgstation.Server.Host.Components.Repository;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Jobs;
|
||||
using Tgstation.Server.Host.System;
|
||||
using Tgstation.Server.Host.Utils;
|
||||
|
||||
@@ -142,7 +143,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
using var windowsByondInstaller = byondInstaller as WindowsByondInstaller;
|
||||
|
||||
// get the bytes for stable
|
||||
return await byondInstaller.DownloadVersion(compatVersion, null, cancellationToken);
|
||||
return await byondInstaller.DownloadVersion(compatVersion, new JobProgressReporter(), cancellationToken);
|
||||
}
|
||||
|
||||
public async Task RunCompatTests(
|
||||
|
||||
Reference in New Issue
Block a user