diff --git a/src/Tgstation.Server.Api/Models/Repository.cs b/src/Tgstation.Server.Api/Models/Repository.cs
index 13a4b48814..004be123cf 100644
--- a/src/Tgstation.Server.Api/Models/Repository.cs
+++ b/src/Tgstation.Server.Api/Models/Repository.cs
@@ -24,7 +24,13 @@ namespace Tgstation.Server.Api.Models
/// If the repository was cloned from GitHub.com. If this enables test merge functionality
///
[Permissions(DenyWrite = true)]
- public bool IsGitHub { get; set; }
+ public bool? IsGitHub { get; set; }
+
+ ///
+ /// Do the equivalent of a git pull. Will attempt to merge unless is also specified
+ ///
+ [Permissions(WriteRight = RepositoryRights.UpdateBranch)]
+ public bool? UpdateReference { get; set; }
///
/// The branch or tag HEAD points to
diff --git a/src/Tgstation.Server.Api/Models/RevisionInformation.cs b/src/Tgstation.Server.Api/Models/RevisionInformation.cs
index 9a3de97f05..0340478d97 100644
--- a/src/Tgstation.Server.Api/Models/RevisionInformation.cs
+++ b/src/Tgstation.Server.Api/Models/RevisionInformation.cs
@@ -5,10 +5,15 @@ namespace Tgstation.Server.Api.Models
///
public sealed class RevisionInformation : Internal.RevisionInformation
{
+ ///
+ /// The that was created with this
+ ///
+ public TestMerge PrimaryTestMerge { get; set; }
+
///
/// The s active in the
///
- public List TestMerges { get; set; }
+ public List ActiveTestMerges { get; set; }
///
/// The s made from the
diff --git a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs
index 10412a6458..23b6d68b47 100644
--- a/src/Tgstation.Server.Host/Components/Repository/IRepository.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/IRepository.cs
@@ -14,6 +14,21 @@ namespace Tgstation.Server.Host.Components.Repository
///
bool IsGitHubRepository { get; }
+ ///
+ /// The if this
+ ///
+ string GitHubOwner { get; }
+
+ ///
+ /// The if this
+ ///
+ string GitHubRepoName { get; }
+
+ ///
+ /// If tracks an upstream branch
+ ///
+ bool Tracking { get; }
+
///
/// The SHA of the HEAD
///
@@ -46,9 +61,8 @@ namespace Tgstation.Server.Host.Components.Repository
/// The e-mail of the merge committer
/// The access string to fetch from the origin repository
/// The for the operation
- /// A string to identify the user that merged
/// A resulting in the SHA of the new HEAD on success, on merge conflict
- Task AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, string mergerIdentifier, CancellationToken cancellationToken);
+ Task AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, CancellationToken cancellationToken);
///
/// Fetch commits from the origin repository
diff --git a/src/Tgstation.Server.Host/Components/Repository/Repository.cs b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
index 3e26156303..13fdf97475 100644
--- a/src/Tgstation.Server.Host/Components/Repository/Repository.cs
+++ b/src/Tgstation.Server.Host/Components/Repository/Repository.cs
@@ -22,6 +22,15 @@ namespace Tgstation.Server.Host.Components.Repository
///
public bool IsGitHubRepository { get; }
+ ///
+ public string GitHubOwner { get; }
+
+ ///
+ public string GitHubRepoName { get; }
+
+ ///
+ public bool Tracking => repository.Head.IsTracking;
+
///
public string Head => repository.Head.Tip.Sha;
@@ -51,6 +60,19 @@ namespace Tgstation.Server.Host.Components.Repository
///
readonly Action onDispose;
+ static void GetRepositoryOwnerName(string remote, out string owner, out string name)
+ {
+ //Assume standard gh format: [(git)|(https)]://github.com/owner/repo(.git)[0-1]
+ //Yes use .git twice in case it was weird
+ var toRemove = new string[] { ".git", "/", ".git" };
+ foreach (string item in toRemove)
+ if (remote.EndsWith(item, StringComparison.OrdinalIgnoreCase))
+ remote = remote.Substring(0, remote.LastIndexOf(item, StringComparison.OrdinalIgnoreCase));
+ var splits = remote.Split('/');
+ name = splits[splits.Length - 1];
+ owner = splits[splits.Length - 2].Split('.')[0];
+ }
+
///
/// Construct a
///
@@ -65,6 +87,12 @@ namespace Tgstation.Server.Host.Components.Repository
this.eventConsumer = eventConsumer ?? throw new ArgumentNullException(nameof(eventConsumer));
this.onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose));
IsGitHubRepository = Origin.ToUpperInvariant().Contains("://GITHUB.COM/");
+ if (IsGitHubRepository)
+ {
+ GetRepositoryOwnerName(Origin, out var owner, out var name);
+ GitHubOwner = owner;
+ GitHubRepoName = name;
+ }
}
///
@@ -106,7 +134,7 @@ namespace Tgstation.Server.Host.Components.Repository
}
///
- public async Task AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, string mergerIdentifier, CancellationToken cancellationToken)
+ public async Task AddTestMerge(int pullRequestNumber, string targetCommit, string committerName, string committerEmail, string accessString, CancellationToken cancellationToken)
{
if (!IsGitHubRepository)
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
index 1a24e7eb71..1afc9a1571 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionControllerFactory.cs
@@ -116,14 +116,14 @@ namespace Tgstation.Server.Host.Components.Watchdog
InstanceName = instance.Name,
Revision = dmbProvider.CompileJob.RevisionInformation
};
- interopInfo.TestMerges.AddRange(dmbProvider.CompileJob.RevisionInformation.TestMerges.Select(x => new TestMerge
+ interopInfo.TestMerges.AddRange(dmbProvider.CompileJob.RevisionInformation.ActiveTestMerges.Select(x => x.TestMerge).Select(x => new TestMerge
{
Author = x.Author,
Body = x.BodyAtMerge,
Comment = x.Comment,
- CommitSha = x.RevisionInformation.CommitSha,
+ CommitSha = x.PrimaryRevisionInformation.CommitSha,
Number = x.Number,
- OriginCommitSha = x.RevisionInformation.OriginCommitSha,
+ OriginCommitSha = x.PrimaryRevisionInformation.OriginCommitSha,
PullRequestCommit = x.PullRequestRevision,
TimeMerged = x.MergedAt.Ticks,
Title = x.TitleAtMerge,
diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
index 1b19f662cb..bded31639d 100644
--- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
+++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs
@@ -3,7 +3,9 @@ using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Linq.Expressions;
using System.Net;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models;
@@ -15,7 +17,7 @@ using Tgstation.Server.Host.Security;
namespace Tgstation.Server.Host.Controllers
{
///
- /// Controller for managing the s
+ /// Controller for managing the s
///
[Route("/" + nameof(Repository))]
public sealed class RepositoryController : ModelController
@@ -25,30 +27,32 @@ namespace Tgstation.Server.Host.Controllers
///
readonly IInstanceManager instanceManager;
+ ///
+ /// The for the
+ ///
+ readonly Octokit.IGitHubClient gitHubClient;
+
///
/// Construct a
///
/// The for the
/// The for the
/// The value of
- public RepositoryController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager) : base(databaseContext, authenticationContextFactory, true)
+ /// The value of
+ public RepositoryController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager, Octokit.IGitHubClient gitHubClient) : base(databaseContext, authenticationContextFactory, true)
{
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
+ this.gitHubClient = gitHubClient ?? throw new ArgumentNullException(nameof(gitHubClient));
}
static string GetAccessString(Api.Models.Internal.RepositorySettings repositorySettings) => repositorySettings.AccessUser != null ? String.Concat(repositorySettings.AccessUser, '@', repositorySettings.AccessToken) : null;
- async Task PopulateApi(Repository model, Components.Repository.IRepository repository, string lastOriginCommitSha, CancellationToken cancellationToken)
+ async Task LoadRevisionInformation(Components.Repository.IRepository repository, Action revInfoSink, CancellationToken cancellationToken)
{
- model.IsGitHub = repository.IsGitHubRepository;
- model.Origin = repository.Origin;
- model.Reference = repository.Reference;
- model.Sha = repository.Head;
-
- //rev info stuff
- var revisionInfo = await DatabaseContext.RevisionInformations.Where(x => x.CommitSha == model.Sha)
+ var repoSha = repository.Head;
+ var revisionInfo = await DatabaseContext.RevisionInformations.Where(x => x.CommitSha == repoSha)
.Include(x => x.CompileJobs)
- .Include(x => x.TestMerges) //minimal info, they can query the rest if they're allowed
+ .Include(x => x.ActiveTestMerges) //minimal info, they can query the rest if they're allowed
.FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false); //search every rev info because LOL SHA COLLISIONS
var needsDbUpdate = revisionInfo == default;
@@ -57,16 +61,30 @@ namespace Tgstation.Server.Host.Controllers
//needs insertion
revisionInfo = new Models.RevisionInformation
{
- CommitSha = model.Sha,
+ CommitSha = repoSha,
CompileJobs = new List(),
- TestMerges = new List(), //non null vals for api returns
- OriginCommitSha = lastOriginCommitSha ?? model.Sha
+ ActiveTestMerges = new List() //non null vals for api returns
};
- DatabaseContext.RevisionInformations.Add(revisionInfo);
- await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
+ lock (DatabaseContext) //cleaner this way
+ DatabaseContext.RevisionInformations.Add(revisionInfo);
}
+ revInfoSink?.Invoke(revisionInfo);
+ return needsDbUpdate;
+ }
+ async Task PopulateApi(Repository model, Components.Repository.IRepository repository, string lastOriginCommitSha, Action revInfoSink, CancellationToken cancellationToken)
+ {
+ model.IsGitHub = repository.IsGitHubRepository;
+ model.Origin = repository.Origin;
+ model.Reference = repository.Reference;
+ model.Sha = repository.Head;
+
+ //rev info stuff
+ Models.RevisionInformation revisionInfo = null;
+ var needsDbUpdate = await LoadRevisionInformation(repository, x => revisionInfo = x, cancellationToken).ConfigureAwait(false);
+ revisionInfo.OriginCommitSha = lastOriginCommitSha ?? model.Sha;
+ revInfoSink?.Invoke(revisionInfo);
model.RevisionInformation = revisionInfo.ToApi();
return needsDbUpdate;
}
@@ -102,7 +120,7 @@ namespace Tgstation.Server.Host.Controllers
//clone conflict
return Conflict();
var api = currentModel.ToApi();
- await PopulateApi(api, repo, null, cancellationToken).ConfigureAwait(false);
+ await PopulateApi(api, repo, null, null, cancellationToken).ConfigureAwait(false);
currentModel.LastOriginCommitSha = repo.Head;
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
return Json(api);
@@ -146,7 +164,164 @@ namespace Tgstation.Server.Host.Controllers
using (var repo = await instanceManager.GetInstance(Instance).RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false))
{
- if (await PopulateApi(api, repo, currentModel.LastOriginCommitSha, cancellationToken).ConfigureAwait(false))
+ if (await PopulateApi(api, repo, currentModel.LastOriginCommitSha, null, cancellationToken).ConfigureAwait(false))
+ await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
+ return Json(api);
+ }
+ }
+
+ ///
+ [TgsAuthorize(RepositoryRights.ChangeAutoUpdateSettings | RepositoryRights.ChangeCommitter | RepositoryRights.ChangeCredentials | RepositoryRights.ChangeTestMergeCommits | RepositoryRights.MergePullRequest | RepositoryRights.SetReference | RepositoryRights.SetSha | RepositoryRights.UpdateBranch)]
+ public override async Task Update([FromBody]Repository model, CancellationToken cancellationToken)
+ {
+ if (model == null)
+ return BadRequest(new { message = "Missing request model!" });
+
+ if (model.AccessUser == null ^ model.AccessToken == null)
+ return BadRequest(new { message = "Either both accessToken and accessUser must be present or neither!" });
+
+ if (model.Sha != null && model.Reference != null)
+ return BadRequest(new { message = "Only one of sha or reference may be specified!" });
+
+ if(model.Sha != null && model.UpdateReference == true)
+ return BadRequest(new { message = "Cannot update a reference when checking out a sha!" });
+
+ if (model.Origin != null)
+ return BadRequest(new { message = "origin cannot be modified without deleting the repository!" });
+
+ var newTestMerges = model.NewTestMerges != null && model.NewTestMerges.Count > 0;
+ var userRights = (RepositoryRights)AuthenticationContext.GetRight(RightsType.Repository);
+ if (newTestMerges && !userRights.HasFlag(RepositoryRights.MergePullRequest))
+ return Forbid();
+
+ var currentModel = await DatabaseContext.RepositorySettings.Where(x => x.InstanceId == Instance.Id).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);
+
+ if (currentModel == default)
+ return StatusCode((int)HttpStatusCode.Gone);
+
+ bool CheckModified(Expression> expression, RepositoryRights requiredRight)
+ {
+ var memberSelectorExpression = (MemberExpression)expression.Body;
+ var property = (PropertyInfo)memberSelectorExpression.Member;
+
+ var newVal = property.GetValue(model);
+ if (newVal == null)
+ return false;
+ if (!userRights.HasFlag(requiredRight) && property.GetValue(currentModel) != newVal)
+ return true;
+
+ property.SetValue(currentModel, newVal);
+ return false;
+ };
+
+ if (CheckModified(x => x.AccessToken, RepositoryRights.ChangeCredentials)
+ || CheckModified(x => x.AccessUser, RepositoryRights.ChangeCredentials)
+ || CheckModified(x => x.AutoUpdatesKeepTestMerges, RepositoryRights.ChangeAutoUpdateSettings)
+ || CheckModified(x => x.AutoUpdatesSynchronize, RepositoryRights.ChangeAutoUpdateSettings)
+ || CheckModified(x => x.CommitterEmail, RepositoryRights.ChangeCommitter)
+ || CheckModified(x => x.CommitterName, RepositoryRights.ChangeCommitter)
+ || CheckModified(x => x.PushTestMergeCommits, RepositoryRights.ChangeTestMergeCommits)
+ || CheckModified(x => x.ShowTestMergeCommitters, RepositoryRights.ChangeTestMergeCommits))
+ return Forbid();
+
+ //so that's the stuff that is just db, the rest is tricky
+
+ using (var repo = await instanceManager.GetInstance(Instance).RepositoryManager.LoadRepository(cancellationToken).ConfigureAwait(false))
+ {
+ if (newTestMerges && !repo.IsGitHubRepository)
+ return Conflict(new { message = "Cannot test merge on a non GitHub based repository!" });
+
+ var committerName = currentModel.ShowTestMergeCommitters.Value ? AuthenticationContext.User.Name : currentModel.CommitterName;
+ var accessString = GetAccessString(currentModel);
+ if (model.UpdateReference == true)
+ {
+ if (!repo.Tracking && model.Reference == null)
+ return Conflict(new { message = "Not on an updatable reference!" });
+ if (!userRights.HasFlag(RepositoryRights.UpdateBranch))
+ return Forbid();
+ await repo.FetchOrigin(accessString, cancellationToken).ConfigureAwait(false);
+ if (model.Sha == null && model.Reference == null)
+ await repo.MergeOrigin(committerName, currentModel.CommitterEmail, cancellationToken).ConfigureAwait(false);
+ }
+
+ if (model.Sha != null || model.Reference != null)
+ {
+ await repo.CheckoutObject(model.Sha ?? model.Reference, cancellationToken).ConfigureAwait(false);
+
+ if (model.UpdateReference == true && model.Reference != null)
+ {
+ if (!repo.Tracking)
+ return Conflict(new { message = "Checked out reference is does not track an object!" });
+ await repo.ResetToOrigin(cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ //now add any testmerges
+ if (newTestMerges)
+ {
+ var repoOwner = repo.GitHubOwner;
+ var repoName = repo.GitHubRepoName;
+ var allAddedTestMerges = new List();
+ foreach (var I in model.NewTestMerges)
+ {
+ await repo.AddTestMerge(I.Number, I.PullRequestRevision, committerName, currentModel.CommitterEmail, accessString, cancellationToken).ConfigureAwait(false);
+
+ Octokit.PullRequest pr = null;
+ string errorMessage = null;
+
+ Models.RevisionInformation revisionInformation = null;
+ var revInfoTask = LoadRevisionInformation(repo, x => revisionInformation = x, cancellationToken);
+
+ try
+ {
+ pr = await gitHubClient.PullRequest.Get(repoOwner, repoName, I.Number).ConfigureAwait(false);
+ }
+ catch (Octokit.RateLimitExceededException)
+ {
+ //you look at your anonymous access and sigh
+ errorMessage = "PRE RATE LIMITED";
+ }
+ catch (Octokit.NotFoundException)
+ {
+ //you look at your shithub access and sigh
+ errorMessage = "PRE NOT FOUND";
+ }
+
+ var attachedContextUser = new Models.User
+ {
+ Id = AuthenticationContext.User.Id
+ };
+ DatabaseContext.Users.Attach(attachedContextUser);
+
+ var tm = new Models.TestMerge
+ {
+ Author = pr?.User.Login ?? errorMessage,
+ BodyAtMerge = pr?.Body,
+ MergedAt = DateTimeOffset.Now,
+ TitleAtMerge = pr?.Title ?? errorMessage,
+ Comment = I.Comment,
+ Number = I.Number,
+ MergedBy = attachedContextUser,
+ PullRequestRevision = I.PullRequestRevision,
+ Url = pr?.HtmlUrl ?? errorMessage
+ };
+ if (pr == null)
+ tm.BodyAtMerge = errorMessage;
+
+ allAddedTestMerges.Add(tm);
+
+ await revInfoTask.ConfigureAwait(false);
+
+ revisionInformation.PrimaryTestMerge = tm;
+ revisionInformation.ActiveTestMerges.AddRange(allAddedTestMerges.Select(x => new RevInfoTestMerge
+ {
+ TestMerge = x
+ }));
+ }
+ }
+
+ var api = currentModel.ToApi();
+ if (await PopulateApi(api, repo, currentModel.LastOriginCommitSha, null, cancellationToken).ConfigureAwait(false) || newTestMerges)
await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
return Json(api);
}
diff --git a/src/Tgstation.Server.Host/Models/DatabaseContext.cs b/src/Tgstation.Server.Host/Models/DatabaseContext.cs
index 5c52b6d5f6..52a16491a4 100644
--- a/src/Tgstation.Server.Host/Models/DatabaseContext.cs
+++ b/src/Tgstation.Server.Host/Models/DatabaseContext.cs
@@ -56,6 +56,11 @@ namespace Tgstation.Server.Host.Models
///
public DbSet ReattachInformations { get; set; }
+ ///
+ /// The s om the
+ ///
+ public DbSet RevInfoTestMerges { get; set; }
+
///
public DbSet WatchdogReattachInformations { get; set; }
@@ -96,9 +101,12 @@ namespace Tgstation.Server.Host.Models
modelBuilder.Entity().HasIndex(x => new { x.UserId, x.InstanceId }).IsUnique();
+ modelBuilder.Entity().HasMany(x => x.RevisonInformations).WithOne(x => x.TestMerge).OnDelete(DeleteBehavior.Cascade);
+
var revInfo = modelBuilder.Entity();
revInfo.HasMany(x => x.CompileJobs).WithOne(x => x.RevisionInformation).OnDelete(DeleteBehavior.Cascade);
- revInfo.HasMany(x => x.TestMerges).WithOne(x => x.RevisionInformation).OnDelete(DeleteBehavior.Cascade);
+ revInfo.HasMany(x => x.ActiveTestMerges).WithOne(x => x.RevisionInformation).OnDelete(DeleteBehavior.Cascade);
+ revInfo.HasOne(x => x.PrimaryTestMerge).WithOne(x => x.PrimaryRevisionInformation).OnDelete(DeleteBehavior.SetNull);
revInfo.HasIndex(x => x.CommitSha).IsUnique();
var chatChannel = modelBuilder.Entity();
diff --git a/src/Tgstation.Server.Host/Models/RepositorySettings.cs b/src/Tgstation.Server.Host/Models/RepositorySettings.cs
index 2a9eef753e..18fda50bfb 100644
--- a/src/Tgstation.Server.Host/Models/RepositorySettings.cs
+++ b/src/Tgstation.Server.Host/Models/RepositorySettings.cs
@@ -24,7 +24,7 @@ namespace Tgstation.Server.Host.Models
///
public Repository ToApi() => new Repository {
- AccessToken = AccessToken,
+ //AccessToken = AccessToken, //never show this
AccessUser = AccessUser,
AutoUpdatesKeepTestMerges = AutoUpdatesKeepTestMerges,
AutoUpdatesSynchronize = AutoUpdatesSynchronize,
diff --git a/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs b/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs
new file mode 100644
index 0000000000..826b124780
--- /dev/null
+++ b/src/Tgstation.Server.Host/Models/RevInfoTestMerge.cs
@@ -0,0 +1,27 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Tgstation.Server.Host.Models
+{
+ ///
+ /// Many to many relationship for and
+ ///
+ public sealed class RevInfoTestMerge
+ {
+ ///
+ /// The row Id
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// The
+ ///
+ [Required]
+ public TestMerge TestMerge { get; set; }
+
+ ///
+ /// The
+ ///
+ [Required]
+ public RevisionInformation RevisionInformation { get; set; }
+ }
+}
diff --git a/src/Tgstation.Server.Host/Models/RevisionInformation.cs b/src/Tgstation.Server.Host/Models/RevisionInformation.cs
index 23db58d0f8..4ff7c0bd79 100644
--- a/src/Tgstation.Server.Host/Models/RevisionInformation.cs
+++ b/src/Tgstation.Server.Host/Models/RevisionInformation.cs
@@ -17,9 +17,14 @@ namespace Tgstation.Server.Host.Models
public Instance Instance { get; set; }
///
- /// See
+ /// See
///
- public List TestMerges { get; set; }
+ public TestMerge PrimaryTestMerge { get; set; }
+
+ ///
+ /// See
+ ///
+ public List ActiveTestMerges { get; set; }
///
/// See s made from this
@@ -31,7 +36,8 @@ namespace Tgstation.Server.Host.Models
{
CommitSha = CommitSha,
OriginCommitSha = OriginCommitSha,
- TestMerges = TestMerges.Select(x => x.ToApi()).ToList(),
+ PrimaryTestMerge = PrimaryTestMerge?.ToApi(),
+ ActiveTestMerges = ActiveTestMerges.Select(x => x.TestMerge.ToApi()).ToList(),
CompileJobs = CompileJobs.Select(x => x.ToApi()).ToList()
};
}
diff --git a/src/Tgstation.Server.Host/Models/TestMerge.cs b/src/Tgstation.Server.Host/Models/TestMerge.cs
index c4f6404f31..2428a192a5 100644
--- a/src/Tgstation.Server.Host/Models/TestMerge.cs
+++ b/src/Tgstation.Server.Host/Models/TestMerge.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
namespace Tgstation.Server.Host.Models
{
@@ -12,10 +13,19 @@ namespace Tgstation.Server.Host.Models
public User MergedBy { get; set; }
///
- /// The for the
+ /// The initial the was merged with
///
- [Required]
- public RevisionInformation RevisionInformation { get; set; }
+ public RevisionInformation PrimaryRevisionInformation { get; set; }
+
+ ///
+ /// Foreign key for
+ ///
+ public long? PrimaryRevisionInformationId { get; set; }
+
+ ///
+ /// All the for the
+ ///
+ public List RevisonInformations { get; set; }
///
public Api.Models.TestMerge ToApi() => new Api.Models.TestMerge
diff --git a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs
index 871269f3ae..7c4aa091f2 100644
--- a/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs
+++ b/src/Tgstation.Server.Host/Security/WindowsSystemIdentityFactory.cs
@@ -64,7 +64,7 @@ namespace Tgstation.Server.Host.Security
var res = NativeMethods.LogonUser(splits.Length > 1 ? splits[1] : splits[0], splits.Length > 1 ? splits[0] : null, password, 3 /*LOGON32_LOGON_NETWORK*/, 0 /*LOGON32_PROVIDER_DEFAULT*/, out var token);
if (!res)
- throw new Win32Exception(Marshal.GetLastWin32Error());
+ return null;
using (var handle = new SafeAccessTokenHandle(token)) //checked internally, windows identity always duplicates the handle when constructed with a userToken
return (ISystemIdentity)new WindowsSystemIdentity(new WindowsIdentity(handle.DangerousGetHandle())); //https://github.com/dotnet/corefx/blob/6ed61acebe3214fcf79b4274f2bb9b55c0604a4d/src/System.Security.Principal.Windows/src/System/Security/Principal/WindowsIdentity.cs#L271